home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / ada_gwu / tasking.c < prev    next >
C/C++ Source or Header  |  1996-01-30  |  78KB  |  2,363 lines

  1. /*
  2.  * Copyright (C) 1985-1992  New York University
  3.  * 
  4.  * This file is part of the Ada/Ed-C system.  See the Ada/Ed README file for
  5.  * warranty (none) and distribution info and also the GNU General Public
  6.  * License for more details.
  7.  
  8.  */
  9.  
  10. /*
  11.       +---------------------------------------------------+
  12.       |                                                   |
  13.       |          I N T E R P         T A S K I N G        |
  14.       |                                                   |
  15.       |                    (C Version)                    |
  16.       |                                                   |
  17.       |   Adapted From Low Level SETL version written by  |
  18.       |                                                   |
  19.       |                  Monte Zweben                     |
  20.       |               Philippe Kruchten                   |
  21.       |               Jean-Pierre Rosen                   |
  22.       |                                                   |
  23.       |    Original High Level SETL version written by    |
  24.       |                                                   |
  25.       |               Robert B. K. Dewar                  |
  26.       |                   Clint Goss                      |
  27.       |               Tracey M. Siesser                   |
  28.       |               Bernard D. Banner                   |
  29.       |               Stephen C. Bryant                   |
  30.       |                  Gerry Fisher                     |
  31.       |                                                   |
  32.       |              C version written by                 |
  33.       |                                                   |
  34.       |               Robert B. K. Dewar                  |
  35.       |                                                   |
  36.       +---------------------------------------------------+
  37. */
  38.  
  39.  
  40. /* Include standard header modules */
  41. #include <stdlib.h>
  42. #include <stdio.h>
  43. #include "config.h"
  44. #include "ipar.h"
  45. #include "ivars.h"
  46. #include "int.h"
  47. #include "tasking.h"
  48. #include "segment.h"
  49. #include "iparp.h"
  50. #include "intap.h"
  51. #include "intbp.h"
  52. #include "intcp.h"
  53. #include "miscp.h"
  54. #include "taskingp.h"
  55.  
  56. #ifdef IBM_PC
  57. #include <time.h>
  58. static void sleep(unsigned);
  59. #endif
  60.  
  61. #ifdef MONITOR
  62. extern int type_of_delay;
  63. extern long Run_Total_Time;
  64. extern int seconds_per_tick;
  65. extern int step_rate;
  66. #endif
  67.  
  68. static void done_creation();
  69. static void create_task(int, int, struct rts_item *, int);
  70. static void done_activation();
  71. static void activate_self(int, int);
  72. static void kill(int);
  73. static void abortme();
  74. static void post_abort_one();
  75. static void post_complete_task_one();
  76. static void post_complete_block();
  77. static void post_complete_block_two();
  78. static void task_term();
  79. static void free_task_space();
  80. static void check_termination(int, int);
  81. static void check_done(int, int);
  82. static void check_unterm();
  83. static void tell_termination(int);
  84. static void uncreate_tasks(int);
  85. static void my_set_timer(struct io_item_type *, long);
  86. static int long my_reset_timer(long);
  87. static void wait(long, int);
  88. static void post_wait();
  89. static void catcher(long);
  90. static struct io_item_type *chain(int, long);
  91. static void check_free(struct io_item_type *);
  92. static int get_io(struct io_item_type *);
  93. static void disable_io(struct io_item_type **);
  94. static int remove_io(struct io_item_type **);
  95. static void schedule(int);
  96. static void finish_action(struct rts_item *);
  97. static void make_ready(int, int);
  98. static void transfer(int);
  99. static void evaluate_guards(int [], int);
  100. static void close_guards(int [], int);
  101. static void post_selective_wait(int, int, int [], int []);
  102. static void accept_rdv(int, int, int);
  103. static void post_entry_call();
  104. static void einit(struct entry_type    *);
  105. static int eremove(int);
  106. static void eput(struct entry_type *, int, struct q_item **);
  107. static int eget(struct entry_type *);
  108. static void add_lock(struct lock_type *);
  109. static void add_unlock(struct lock_type *);
  110. static void del_lock(struct lock_type *);
  111. static void del_unlock(struct lock_type *);
  112. static int entry_number(int, int, int);
  113. static void multisignal(int, int);
  114. static void add_serviced(int, int);
  115. static int remove_serviced();
  116. static void qinit();
  117. static void enqueue(int, int);
  118. static void enqueue_item(int, struct rts_item *);
  119. static struct rts_item *dequeue(struct ready_q *, int *);
  120. static void context_switch();
  121.  
  122. /* Global variables for tasking management */
  123.  
  124. /* id of the owner of the corr. stack */
  125. static int original_task[MAX_TASKS];
  126. /* Head of task chained waiting on clock */
  127. static struct io_item_type *clock_head;
  128. /* Highest priority of tasks to schedule */
  129. static int highest_priority;
  130. /* Previous value of time */
  131. static long last_time;
  132. /* temporary decl of ready queues  */
  133. static struct ready_q *ready_queue[MAX_PRIO];
  134.  
  135. /*-------------------------------------------------------------------------*
  136.  *                ----  T A S K I N G    S Y S T E M   ---                 *
  137.  *                                                                         *
  138.  *  The module contains all of the tasking control routines.  It is        *
  139.  *  divided into nine major sections.  Itemized under each section are the *
  140.  *  routines which are callable from outside the tasking module.  Unless   *
  141.  *  interface changes are made it is essential that the status of the      *
  142.  *  stack, on entry and exit from these routines, be maintained.           *
  143.  *                                                                         *
  144.  *      - Task Initialization                                              *
  145.  *               * initialize_tasking                                      *
  146.  *      - Task Creation                                                    *
  147.  *               * start_creation                                          *
  148.  *      - Task Activation                                                  *
  149.  *               * start_activation                                        *
  150.  *               * union_tasks_declared                                    *
  151.  *               * end_activation                                          *
  152.  *      - Task Abortion                                                    *
  153.  *               * abort                                                   *
  154.  *      - Task Termination                                                 *
  155.  *               * complete_task                                           *
  156.  *               * complete_block                                          *
  157.  *               * terminate_unactivated                                   *
  158.  *               * purge_rdv                                               *
  159.  *      - Timer Maintainence                                               *
  160.  *               * delay_stmt                                              *
  161.  *               * clock_interrupt                                         *
  162.  *      - Task Scheduler                                                   *
  163.  *               * round_robin                                             *
  164.  *      - Rendezvous                                                       *
  165.  *               * entry_call                                              *
  166.  *               * selective_wait                                          *
  167.  *               * end_rendezvous                                          *
  168.  *      - Utility Routines (queue routines etc.                            *
  169.  *               * raise_in_caller                                         *
  170.  *               * is_callable                                             *
  171.  *               * is_terminated                                           *
  172.  *               * count                                                   *
  173.  *                                                                         *
  174.  *-------------------------------------------------------------------------*/
  175.  
  176.  
  177. /*-------------------------------------------------------------------------*/
  178. /*            T A S K I N G    I N I T I A L I Z A T I O N                 */
  179. /*                                                                         */
  180. /*  Procedure to perform necessary initialization for tasking system       */
  181. /*-------------------------------------------------------------------------*/
  182.  
  183. void initialize_tasking()                            /*;initialize_tasking*/
  184. {
  185.     int     i;
  186.     int    *p;
  187.     long   itime();
  188.  
  189.     /*  Initialize variables */
  190.  
  191.     last_task = 1;
  192.  
  193.     for (i = 0; i < MAX_TASKS; i++) {
  194.         STACK(i) = (int *)0;
  195.         ORIG(i) = NULL_TASK;
  196.     }
  197.     qinit();
  198.     time_offset = 0;
  199.     last_time = itime();
  200.     clock_head = NULL;
  201.     next_clock = itime();
  202.     next_clock_flag = FALSE;
  203.     rr_counter = 0;
  204.  
  205.     /*  Initiate the idle task */
  206.  
  207.     p = STACK(0) = (int *) malloc((unsigned) sizeof(int) * main_task_size);
  208.     ORIG(0) = 0;
  209.     if (p == (int *)0) {
  210.         printf("Unable to allocate stack\n");
  211.         exit(RC_ABORT);
  212.     }
  213.  
  214.     TCB_ABNORMAL(0)      = 0;
  215.     TCB_ACTION(0)           = NO_ACTION;
  216.     TCB_BROTHER(0)         = 0;
  217.     TCB_BLOCK_PTR(0)     = (int *) 0;
  218.     TCB_CURR_ENTRY(0)     = NULL;
  219.     TCB_EVENT(0)         = NO_EVENT;
  220.     TCB_EXCEPTION(0)       = 0;
  221.     TCB_ENTRY_ITEM(0)     = 0;
  222.     TCB_FIRST(0)         = 0;
  223.     TCB_ID(0)             = 0;
  224.     TCB_IO_ITEM(0)         = NULL;
  225.     TCB_MASTER_TASK(0)     = NULL_TASK;
  226.     TCB_MASTER_BLOCK(0)     = 0;
  227.     TCB_NEXT(0)               = NULL_TASK;
  228.     TCB_NUM_ITEMS(0)       = 0;
  229.     TCB_NUM_NOTERM(0)       = 0;
  230.     TCB_NUM_DEPS(0)      = 0;
  231.     TCB_NUM_ENTRIES(0)   = 0;
  232.     TCB_NUM_EVENTS(0)       = 0;
  233.     TCB_PARENT(0)          = NULL_TASK;
  234.     TCB_PRIO(0)           = 0;
  235.     TCB_RDV(0)           = 0;
  236.     TCB_RTS_ITEM(0)         = NULL;
  237.     TCB_SAVE_PRIO(0)     = 0;
  238.     TCB_SERVICED(0)       = 0;
  239.     TCB_STATUS(0)           = ACTIVE;
  240.     TCB_TBASE(0)         = 1;
  241.     TCB_TOFF(0)             = 52;
  242.     TCB_WHAT(0)           = 0;
  243.     TCB_WHO(0)           = NULL_TASK;
  244.  
  245.     /*  Set context for idle task */
  246.  
  247.     STACKPTR(0) = WORDS_TCB;
  248.     tp = 0;
  249.     cur_stack = STACK(tp);
  250.     cur_stackptr = STACKPTR(tp);
  251.     bfp = 0;
  252.     ip = TASK_CODE_OFFSET;
  253.     cs = 1;
  254.     sfp = 0;
  255.     lin = 0;
  256.     exr = 0;
  257.     cur_code = code_segments[cs];
  258. }
  259.  
  260.  
  261. /*--------------------------------------------------------------------------*/
  262. /*                     T A S K    C R E A T I O N                           */
  263. /*                                                                          */
  264. /*  The following set of routines perform task creation                     */
  265. /*--------------------------------------------------------------------------*/
  266.  
  267. /*-------------------------------------------------------------------------*/
  268. /*                             START  CREATION                             */
  269. /*  Create an array of tasks, do so by creating a RTS item for the array   */
  270. /*  As tasks become ready to run they will perform activations etc. first  */
  271. /*  using this RTS item                                                    */
  272. /*-------------------------------------------------------------------------*/
  273.  
  274. void start_creation(int templ_base, int templ_off)            /*;start_creation*/
  275. {
  276.     int    mult = 1;
  277.     struct rts_item     *rts;
  278.  
  279.     if (BLOCK_FRAME->bf_tasks_declared == NULL)
  280.         push_task_frame(NULL_TASK);        /* create null frame */
  281.  
  282.     rts = (struct rts_item *) malloc(sizeof(struct rts_item));
  283.     if (rts == (struct rts_item *)0) {
  284.         raise(STORAGE_ERROR, "Allocating space for task");
  285.         return;
  286.     }
  287.     rts->tcbs = (int *) malloc((unsigned) sizeof(int)*mult);
  288.     if (rts->tcbs == (int *)0) {
  289.         raise(STORAGE_ERROR, "Allocating space for task");
  290.         return;
  291.     }
  292.     RTS_TYPE(rts) = CREATE;
  293.     RTS_PRIO(rts) = MY_PRIO;
  294.     RTS_TEMPL_BASE(rts) = templ_base;
  295.     RTS_TEMPL_OFF(rts) = templ_off;
  296.     RTS_MULT(rts) = mult;
  297.     RTS_NEXT(rts) = NULL;
  298.     RTS_PARENT(rts) = tp;
  299.  
  300.     MY_WHAT = NULL_TASK;
  301.     MY_NUM_ITEMS = mult;
  302.     enqueue_item(MY_PRIO, rts);
  303.     schedule(DONE_CREATION);
  304. }
  305.  
  306. /*--------------------------------------------------------------------------*/
  307. /*                             DONE   CREATION                              */
  308. /*   Performed after all of my tasks have finished creation.  Add current   */
  309. /*   RTS item to chain                                                      */
  310. /*--------------------------------------------------------------------------*/
  311.  
  312. static void done_creation()                                    /*;done_creation*/
  313. {
  314.     if (MY_EXCEPTION == STORAGE_ERROR) {
  315.         raise(STORAGE_ERROR, "Not enough space for new tasks");
  316.         MY_EXCEPTION = 0;
  317.     }
  318.     if (MY_WHAT != NULL_TASK)         /* MY_WHAT is leader of RTS */
  319.         TCB_BROTHER(MY_WHAT) = FAS(MY_TASKS_DECLARED, MY_WHAT);
  320.     PUSH(MY_WHAT); /* Must add item to chain of rts items */
  321. }
  322.  
  323. /*-----------------------------------------------------------------------*/
  324. /*                            CREATE  TASK                               */
  325. /*  Procedure to create task and put it on parents frame chain           */
  326. /*-----------------------------------------------------------------------*/
  327.  
  328. static void create_task(int templ_base, int templ_off, struct rts_item *rts,
  329.   int my_id)                                                    /*;create_task*/
  330. {
  331.     int     task_nr, parent;    /* nr of the task to be created */
  332.     int     i, *p, old_last_task;    /* temporary variable */
  333.  
  334.     /* STEP 1: Search the stack_segments for a stack */
  335.  
  336.     old_last_task = last_task;
  337.     task_nr = INC(last_task);
  338.     parent = RTS_PARENT(rts);
  339.     for(;task_nr < old_last_task + MAX_TASKS; task_nr = INC(last_task))
  340.         if (ORIG(task_nr) == NULL_TASK) break;
  341.     if (task_nr >= old_last_task + MAX_TASKS) {/* Error if no avail stack */
  342.         FAS(&(TCB_EXCEPTION(parent)),PROGRAM_ERROR);
  343.         multisignal(parent, NO_EVENT);
  344.         return;
  345.     }
  346.  
  347.     /* STEP 2: Create task frame for new task */
  348.  
  349.     p=STACK(task_nr) = (int *) malloc((unsigned) sizeof(int)*new_task_size);
  350.     ORIG(task_nr) = task_nr;
  351.  
  352.     /* STEP 3 : Create storage area for task and initialize */
  353.     if (p == (int *)0) {
  354.         RTS_TCBS(rts, my_id) = NULL_TASK;
  355.         DEC(RTS_MULT(rts));
  356.         FAS(&(TCB_EXCEPTION(parent)), STORAGE_ERROR);
  357.         STACKPTR(task_nr) = 0;
  358.         multisignal(parent, NO_EVENT);
  359.     }
  360.     else {
  361.         TCB_ABNORMAL(task_nr)       = 0;
  362.         TCB_ACTION(task_nr)       = ACTIVATE_SELF;
  363.         TCB_BLOCK_PTR(task_nr)       = (int *) 0;
  364.         TCB_BROTHER(task_nr)       = NULL_BROTHER;
  365.         TCB_CURR_ENTRY(task_nr)   = NULL;
  366.         TCB_ENTRY_ITEM(task_nr)   = NULL;
  367.         TCB_EVENT(task_nr)           = NO_EVENT;
  368.         TCB_EXCEPTION(task_nr)    = 0;
  369.         TCB_FIRST(task_nr)          = 0;
  370.         TCB_ID(task_nr)              = my_id;
  371.         TCB_IO_ITEM(task_nr)       = NULL;
  372.         TCB_MASTER_BLOCK(task_nr) = 0;
  373.         TCB_MASTER_TASK(task_nr)  = NULL_TASK;
  374.         TCB_NEXT(task_nr)           = NULL_TASK;
  375.         TCB_NUM_ITEMS(task_nr)       = 0;
  376.         TCB_NUM_DEPS(task_nr)       = 0;
  377.         TCB_NUM_ENTRIES(task_nr)  =
  378.           TASK(ADDR(templ_base,templ_off))->nb_entries;
  379.         TCB_NUM_EVENTS(task_nr)   = 0;
  380.         TCB_NUM_NOTERM(task_nr)   = 0;
  381.         TCB_PARENT(task_nr)       = RTS_PARENT(rts);
  382.         TCB_PRIO(task_nr)         = TASK(ADDR(templ_base, templ_off))->priority;
  383.         TCB_RDV(task_nr)            = 0;
  384.         TCB_RTS_ITEM(task_nr)     = rts;
  385.         TCB_SAVE_PRIO(task_nr)      = 0;
  386.         TCB_SERVICED(task_nr)       = NULL_TASK;
  387.         TCB_STATUS(task_nr)       = ACTIVATING;
  388.         TCB_TBASE(task_nr)           = templ_base;
  389.         TCB_TOFF(task_nr)           = templ_off + WORDS_TASK;
  390.         TCB_WHAT(task_nr)           = 0;
  391.         TCB_WHO(task_nr)           = NULL_TASK;
  392.  
  393.         /* add space for queue headers */
  394.  
  395.         for (i=1; i<=TASK(ADDR(templ_base,templ_off))->nb_entries; i++)
  396.             einit(TCB_ENTRY(task_nr, i));
  397.         p = (int *)(TCB_ENTRY(task_nr, i));
  398.  
  399.         *p++ = 0;        /* EXR */
  400.         *p++ = 0;        /* LIN */
  401.         *p++ = 0;        /* SFP */
  402.         *p++ = 0;        /* CS */
  403.         *p++ = 0;        /* IP */
  404.         STACKPTR(task_nr) = p - STACK(task_nr);
  405.         *p++ = 0;        /* BFP */
  406. #ifdef GWUMON
  407.         CWK_CHANGE_TASK_STAT(task_nr, 'C', 
  408.             TASK(ADDR(templ_base,templ_off))->task_name,
  409.              TASK(ADDR(templ_base,templ_off))->task_file);
  410. #endif
  411. #ifdef TRACE
  412.         if(tasking_trace)
  413.             printf("task %d creating task %d\n",tp,task_nr);
  414. #endif
  415.         RTS_TCBS(TCB_RTS_ITEM(task_nr), TCB_ID(task_nr)) = task_nr;
  416.         TCB_WHAT(TCB_PARENT(task_nr)) = task_nr;
  417.         multisignal(RTS_PARENT(TCB_RTS_ITEM(task_nr)), NO_EVENT);
  418.     }
  419. }
  420.  
  421. /*--------------------------------------------------------------------------*
  422.  *                     T A S K    A C T I V A T I O N                       *
  423.  *                                                                          *
  424.  *  The following set of routines perform task activation                   *
  425.  *--------------------------------------------------------------------------*/
  426.  
  427.  
  428. /*--------------------------------------------------------------------------*
  429.  *                         START  ACTIVATION                                *
  430.  *  This routines is used by a task to preprocess it's task list in order   *
  431.  *  to find out how many tasks must be activated.  It then adds the items   *
  432.  *  in the tasks list to the ready queue in order that they may then be     *
  433.  *  activated in parallel.  When they are done being activated, the parent  *
  434.  *  task may continue processing.                                           *
  435.  *--------------------------------------------------------------------------*/
  436.  
  437. void start_activation(int task_list, int task_master, int task_block)
  438.                                                         /*;start_activation*/
  439. {
  440.     int    i, task, next_task, num_tasks;
  441.     struct rts_item    *item;
  442.  
  443.     if (MY_ABNORMAL) {
  444.         uncreate_tasks(task_list);
  445.         abortme();
  446.         return;
  447.     }
  448.  
  449.     task = task_list;
  450.     num_tasks = 0;
  451.     while (task != NULL_TASK) {
  452.         num_tasks += RTS_MULT(TCB_RTS_ITEM(task));
  453.         task = TCB_BROTHER(task);
  454.     }
  455.     MY_NUM_ITEMS = num_tasks;
  456.     MY_EVENT = NO_EVENT;
  457.  
  458.     if (TCB_ABNORMAL(task_master)) return;
  459.  
  460.     MY_STATUS = ACTIVATING;
  461.     task = task_list;
  462.     for (i=0;i<num_tasks;i++) {
  463.         next_task = TCB_BROTHER(task);
  464.         item = TCB_RTS_ITEM(task);
  465.         RTS_MASTER_TASK(item) = task_master;
  466.         RTS_MASTER_BLOCK(item) = task_block;
  467.         RTS_PRIO(item) = MY_PRIO;
  468.         RTS_TYPE(item) = ACTIVATE;
  469.         RTS_NEXT(item) = NULL;
  470.         enqueue_item(MY_PRIO, item);
  471.         task = next_task;
  472.     }
  473.     schedule(DONE_ACTIVATION);
  474. }
  475.  
  476. /*--------------------------------------------------------------------------*/
  477. /*                         DONE   ACTIVATION                                */
  478. /*  This routines is called by the parent task when all of its tasks have   */
  479. /*  finished their activation.  It checks that it is ok, if not it aborts   */
  480. /*  all of the children.                                                    */
  481. /*--------------------------------------------------------------------------*/
  482.  
  483. static void done_activation()                             /*;done_activation*/
  484. {
  485.     if (MY_ABNORMAL) {
  486.         abortme();
  487.         return;
  488.     }
  489.     if (MY_EVENT == TASKERR_EVENT) {
  490.         raise(TASKING_ERROR, "Tasking error in activation");
  491.         MY_EXCEPTION = 0;
  492.     }
  493.     else if (MY_EVENT == PROGERR_EVENT) {
  494.         raise(PROGRAM_ERROR, "Activating an unelaborated task");
  495.         MY_EXCEPTION = 0;
  496.     }
  497.     MY_ACTION = NO_ACTION;
  498. }
  499.  
  500. int union_tasks_declared(int list1, int list2)        /*;union_tasks_declared */
  501. {
  502.     int    head2, tail1;
  503.  
  504.     if (list1 == NULL_TASK) return list2;
  505.     if (list2 == NULL_TASK) return list1;
  506.  
  507.     tail1 = list1;
  508.     while (TCB_BROTHER(tail1) != NULL_TASK) tail1 = TCB_BROTHER(tail1);
  509.  
  510.     head2 = FAS(&(list2), list1);
  511.     FAS(&(TCB_BROTHER(tail1)), head2);
  512.     return list1;
  513. }
  514.  
  515. /*------------------------------------------------------------------------*/
  516. /*                  TASK  ACTIVATION                                         */
  517. /* Procedure to activate self and put on the bf_subtasks chain if leader  */
  518. /*------------------------------------------------------------------------*/
  519.  
  520. static void activate_self(int task_master, int task_bfp)     /*;activate_self*/
  521. {
  522.     int    *ptr;                  /* memory address */
  523.     int     i, val1, val2, tmp_base, tmp_off; /* temporary base */
  524.  
  525.     if (MY_BROTHER != NULL_BROTHER)     /* I am leader of RTS */
  526.         MY_BROTHER =
  527.           FAS(&(((struct bf *)(STACK(task_master)+task_bfp))->bf_subtasks), tp);
  528.  
  529.     if (MY_STATUS == TERMINATED || MY_ABNORMAL) { /* may have been aborted */
  530.         MY_STATUS = TERMINATED;
  531.         multisignal(MY_PARENT, NO_EVENT);
  532.         schedule(NO_ACTION);
  533.         return;
  534.     }
  535.  
  536.     MY_MASTER_TASK = task_master;
  537.     MY_MASTER_BLOCK= task_bfp;
  538.     MY_NUM_NOTERM = 1;         /* myself */
  539.     MY_NUM_DEPS = 1;         /* myself */
  540.  
  541.     ptr = ADDR(MY_TBASE, MY_TOFF-WORDS_TASK);
  542.     tmp_base = TASK(ptr)->body_base;
  543.     tmp_off = TASK(ptr)->body_off;
  544.     ptr = ADDR(tmp_base, tmp_off);
  545.     cs = *ptr;
  546.     if (cs < 1) {    /* Not elaborated !! TBSL */
  547.         TCB_EXCEPTION(MY_PARENT) = PROGRAM_ERROR;
  548.         multisignal(MY_PARENT, PROGERR_EVENT);
  549.         schedule(NO_ACTION);
  550.         return;
  551.     }
  552.     ip = TASK_CODE_OFFSET;
  553.  
  554.     /* reserve space for local variables */
  555.     /* note: this could be somehow optimized by just moving */
  556.     /*   the Top of Stack.... */
  557.  
  558. #ifdef ALIGN_WORD
  559.     val1 = get_int((int *)(code_segments[cs] + code_seglen[cs] - sizeof(int)
  560.       -1));
  561. #else
  562.     val1 = *(int *)(code_segments[cs] + code_seglen[cs] - sizeof(int) - 1);
  563. #endif
  564.     for (i = 0; i < val1; i++)
  565.         PUSH(0);
  566.  
  567.     i = cur_stackptr + NB_REGISTERS - 1;
  568.     PUSH(i);        /* SFP -- this is a trap */
  569.     PUSH(cs);        /* CS */
  570.     PUSH(lin);      /* LIN*/
  571.     PUSH(ip);        /* IP */
  572.     sfp = cur_stackptr + 1;
  573.     /* copy relay set */
  574.  
  575.     val2 = *++ptr * 2;    /* length */
  576.     for (i = 0; i < val2; i++)
  577.         PUSH(*++ptr);
  578.  
  579.     /* Dummy block frame for trapping exceptions */
  580.     PUSH(0);        /* bfp */
  581.     bfp = cur_stackptr;
  582.     PUSHP(0L);        /* data_link */
  583.     PUSHP(0L);        /* tasks_declared */
  584.     PUSH(1);        /* num_noterm */
  585.     PUSH(1);        /* num_deps */
  586.     PUSH(NULL_TASK);/* subtasks */
  587.     PUSH(2);        /* exception vector */
  588.     cur_code = code_segments[cs];
  589.  
  590.     /* This must occur after possible to detect all errors */
  591.  
  592.     INC(TCB_NUM_NOTERM(MY_MASTER_TASK));
  593.     INC(TCB_NUM_DEPS(MY_MASTER_TASK));
  594.     INC(BF_NUM_NOTERM(MY_MASTER_TASK, MY_MASTER_BLOCK));
  595.     INC(BF_NUM_DEPS(MY_MASTER_TASK, MY_MASTER_BLOCK));
  596.  
  597. #ifdef GWUMON
  598.         CWK_CHANGE_TASK_STAT(tp, 'A', "", "" );
  599. #endif
  600. #ifdef TRACE
  601.     if (tasking_trace) {
  602.         printf("task %d activating task %d\n",task_master,tp);
  603.     }
  604. #endif
  605. }
  606.  
  607.  
  608. /*-------------------------------------------------------------------------*/
  609. /*                            END  ACTIVATION                              */
  610. /* Procedure called at the end of activation to signal the parent task     */
  611. /* that everything is OK (or not as the case may be)                       */
  612. /*-------------------------------------------------------------------------*/
  613.  
  614. void end_activation(int term_code)                 /*;end_activation*/
  615. {
  616.     /* after we passed the end of activation, the exception vector */
  617.     /* of the very first block shall designate the task_trap. */
  618.  
  619.     BF_HANDLER(tp, MY_PREVIOUS_BFP) = 2;
  620.     if (term_code == 0) {
  621.         TCB_EXCEPTION(MY_PARENT) = TASKING_ERROR;
  622.         DEC(RTS_MULT(MY_RTS_ITEM));
  623.         RTS_TCBS(MY_RTS_ITEM, MY_ID) = NULL_TASK;
  624.         multisignal(MY_PARENT, TASKERR_EVENT);
  625.     }
  626.     else {
  627.         MY_STATUS = ACTIVE;
  628.         multisignal(MY_PARENT, NO_EVENT);
  629.     }
  630. }
  631.  
  632. /*--------------------------------------------------------------------------*/
  633. /*                  A B O R T    R O U T I N E S                            */
  634. /*--------------------------------------------------------------------------*/
  635.  
  636. /*--------------------------------------------------------------------------*/
  637. /*                                 ABORT                                    */
  638. /* Procedure used to abort nr_task tasks whose numbers are on the stack     */
  639. /*--------------------------------------------------------------------------*/
  640.  
  641. void abort(int nr_tasks)                                         /*;abort*/
  642. {
  643.     int     current;    /* pointer to the task currently aborting */
  644.     int     i;        /* temporary loop index */
  645.  
  646.     for (i = 0; i < nr_tasks; i++) {
  647.         POP(current);
  648.         kill(current);
  649.     }
  650.     if (MY_ABNORMAL)   /* Suicide! */
  651.         abortme();
  652. }
  653.  
  654. /*--------------------------------------------------------------------------*/
  655. /*                       KILL                                                */
  656. /* Procedure to abort task, after having aborted its dependent tasks. If    */
  657. /* nobody in the family is engaged in a rendezvous, then the task is made   */
  658. /* terminated and space of dependent tasks is released. This procedure does */
  659. /* not call WAIT: this has to be done by the caller if it aborts itself.    */
  660. /*--------------------------------------------------------------------------*/
  661.  
  662. static void kill(int task)                                            /*;kill*/
  663. {
  664.     int      task2, dep, i, j, block;
  665.  
  666.     /* STEP 1: Check status etc. of task being aborted ...  */
  667.  
  668.     if (INC(TCB_ABNORMAL(task)) || (TCB_STATUS(task) == TERMINATED)) {
  669.         /* more than one task trying to abort it, must clean up ... */
  670. #ifdef GWUMON
  671.             CWK_CHANGE_TASK_STAT(task, 'E', "", "" );
  672. #endif
  673. #ifdef TRACE
  674.         if (tasking_trace)
  675.             printf("task %d aborting terminated task %d\n",tp,task);
  676. #endif
  677.         DEC(TCB_ABNORMAL(task));        /* avoid overflow */
  678.         return;
  679.     }
  680.  
  681. #ifdef GWUMON
  682.             CWK_CHANGE_TASK_STAT(task, 'E', "", "" );
  683. #endif
  684. #ifdef TRACE
  685.     if (tasking_trace && TCB_ABNORMAL(task))
  686.         printf("task %d aborting task %d\n",tp,task);
  687. #endif
  688.  
  689.     /* STEP 2:  Kill all dependent tasks by block
  690.      *        I can spawn tasks and use a multi-wait count here to make sure done
  691.      */
  692.     if (TCB_BLOCK_PTR(task) == NULL) block = 0;  /* no yet activated ... */
  693.     else block = *(TCB_BLOCK_PTR(task));
  694.     while (block != 0) {
  695.         task2 = BF_SUBTASKS(task, block);
  696.         while (task2 != NULL_TASK) {
  697.             i = 0; 
  698.             j = 0;
  699.             while (i < RTS_MULT(TCB_RTS_ITEM(task2)))
  700.                 if ((dep=RTS_TCBS(TCB_RTS_ITEM(task2),j++)) != NULL_TASK) {
  701.                     i++;
  702.                     kill(dep);
  703.                 }
  704.             task2 = TCB_BROTHER(task2);
  705.         }
  706.         block = BF_PREVIOUS_BFP(task, block);
  707.     }
  708.     /* STEP 3: Perform cleanup. Try to disable task if it waiting, if
  709.      *    successful then must signal.  Otherwise it will discover itself
  710.      *    when awakens or when it reaches a synchronization point (when it
  711.      *    is 'active' but paused by the round-robin scheduling scheme).
  712.      */
  713.     switch (TCB_STATUS(task)) {
  714.     case COMPLETED      :
  715.     case ACTIVATING     :
  716.     case ACTIVE         :
  717.     case COMPLETE_BLOCK :
  718.         break;
  719.     case SELECTING_TERM:
  720.     case SELECTING_NOTERM:
  721.         if (FAS(&(TCB_RDV(task)),0) == 1)
  722.             make_ready(task, ABORT_EVENT);            
  723.         break;
  724.     case TIMED_RDV:
  725.     case CALLING_RDV:
  726.         if (eremove(task)) make_ready(task, ABORT_EVENT); 
  727.         break;
  728.     case WAIT:
  729.         if (remove_io(&(TCB_IO_ITEM(task))))
  730.             make_ready(task, ABORT_EVENT);            
  731.         break;
  732.     default: 
  733.         raise(SYSTEM_ERROR, "Aborting task in unknown state");
  734.         break;
  735.     } /* status TERMINATED & ABNORMAL already tested in kill.
  736.        * QUIESCENT depends on ABNORMAL (Cf post_selective_wait & abortme)
  737.        * COMPLETE_BLOCK and ACTIVE have been added (Cf round-robin)
  738.        */
  739.  
  740. }
  741.  
  742. /*--------------------------------------------------------------------------*/
  743. /*                       ABORTME                                             */
  744. /* Task has discovered it was aborted. kids in select term have been sig-   */
  745. /* nalled.  Completed kids will be notified when their kids are through.    */
  746. /* My terminated kids are already done.                                     */
  747. /*--------------------------------------------------------------------------*/
  748.  
  749. static void abortme()                            /*;abortme */
  750. {
  751.     purge_rdv(tp);
  752.     if ((MY_STATUS != QUIESCENT) && (DEC(MY_NUM_NOTERM) != 1)) {
  753.         MY_STATUS = COMPLETED;
  754.         schedule(ABORT_ONE);
  755.     }
  756.     else post_abort_one();
  757. }
  758.  
  759. static void post_abort_one()                                /*;post_abort_one*/
  760. {
  761.     if (MY_STATUS != QUIESCENT)
  762.         check_termination(MY_MASTER_TASK, MY_MASTER_BLOCK);
  763.     task_term();    /* not strictly needed for abort, just "term-wave" */
  764. }
  765.  
  766. /*--------------------------------------------------------------------------*/
  767. /*                           T E R M I N A T I O N                          */
  768. /*                                                                          */
  769. /*  The following set of routines maintain the counters and data structures */
  770. /*  used to perform task temination.  They are divided into two sets: those */
  771. /*  used in the termination of blocks and subprograms and those used in the */
  772. /*  termination of tasks.                                                   */
  773. /*--------------------------------------------------------------------------*/
  774.  
  775.  
  776. /*--------------------------------------------------------------------------*/
  777. /*                          COMPLETE  TASK                                  */
  778. /*  This is the last instruction in a task's instruction stream             */
  779. /*--------------------------------------------------------------------------*/
  780.  
  781. void complete_task()                                        /*;complete_task*/
  782. {
  783.     MY_STATUS = COMPLETED;
  784.     if (DEC(MY_NUM_NOTERM) != 1) schedule(COMPLETE_TASK_ONE);
  785.     else post_complete_task_one();
  786. }
  787.  
  788. static void post_complete_task_one()                /*;post_complete_task_one*/
  789. {
  790.     check_termination(MY_MASTER_TASK, MY_MASTER_BLOCK);
  791.     if (INC(MY_ABNORMAL) == 0)
  792.         task_term();
  793.     else if (DEC(MY_NUM_DEPS) != 1) schedule(FREE_TASK_SPACE);
  794.     else free_task_space();
  795. }
  796.  
  797. /*--------------------------------------------------------------------------*/
  798. /*                              COMPLETE  BLOCK                             */
  799. /*--------------------------------------------------------------------------*/
  800.  
  801. void complete_block()                                        /*;complete_block*/
  802. {
  803.     MY_STATUS = COMPLETE_BLOCK;
  804.     if (DEC(MY_BF_NUM_NOTERM) != 1)
  805.         schedule(COMPLETE_BLOCK_ONE);
  806.     else post_complete_block();
  807. }
  808.  
  809. static void post_complete_block()                        /*;post_complete_block*/
  810. {
  811.     if (MY_ABNORMAL == 0)
  812.         tell_termination(*MY_BLOCK_PTR);
  813.     if (DEC(MY_BF_NUM_DEPS) != 1)    schedule(COMPLETE_BLOCK_TWO);
  814.     else post_complete_block_two();
  815. }
  816.  
  817. static void post_complete_block_two()            /*;post_complete_block_two*/
  818. {
  819.     MY_STATUS = ACTIVE;
  820. }
  821.  
  822. /*--------------------------------------------------------------------------*/
  823. /*                     TERMINATION  SUPPORT  ROUTINES                       */
  824. /*--------------------------------------------------------------------------*/
  825.  
  826. static void task_term()                                            /*;task_term*/
  827. {
  828.     int block;
  829.  
  830.     if (DEC(MY_NUM_DEPS) != 1) {
  831.         block = *MY_BLOCK_PTR;
  832.         while (block != 0) {
  833.             tell_termination(block);
  834.             block = BF_PREVIOUS_BFP(tp, block);
  835.         }
  836.         schedule(FREE_TASK_SPACE);
  837.     }
  838.     else free_task_space();
  839. }
  840.  
  841. static void free_task_space()                            /*;free_task_space */
  842. {
  843.     int    block;
  844.  
  845.     block = *MY_BLOCK_PTR;
  846.     while (block != 0) {
  847.         uncreate_tasks(BF_SUBTASKS(tp, block));
  848.         block = BF_PREVIOUS_BFP(tp, block);
  849.     }
  850.     MY_STATUS = TERMINATED;
  851.     check_done(MY_MASTER_TASK, MY_MASTER_BLOCK);
  852.     schedule(NO_ACTION);
  853. }
  854.  
  855. /* Recursive procedure to check master tasks and blocks called by quiescent */
  856. /* dependent of "task" and "block"                         */
  857.  
  858. static void check_termination(int task, int block)        /*;check_termination */
  859. {
  860.     if ((task != NULL_TASK) && (task != 0) && (DEC(TCB_NUM_NOTERM(task)) == 1))
  861.         if ((TCB_STATUS(task) == COMPLETED) && (INC(TCB_FIRST(task)) == 0)) {
  862.             if (TCB_NUM_NOTERM(task) == 0)
  863.                 make_ready(task, TERMINATE_EVENT);
  864.         }
  865.         else
  866.             check_termination(TCB_MASTER_TASK(task),TCB_MASTER_BLOCK(task));
  867.  
  868.     if ((block != 0) && (DEC(BF_NUM_NOTERM(task, block)) == 1))
  869.         make_ready(task, TERMINATE_EVENT);
  870. }
  871.  
  872. static void check_done(int task, int block)                        /*;check_done*/
  873. {
  874.     int    dd;
  875.     dd = DEC(TCB_NUM_DEPS(task));
  876.     if ((DEC(BF_NUM_DEPS(task, block)) == 1) || (dd == 1))
  877.         make_ready(task, NO_EVENT);
  878. }
  879.  
  880. static void check_unterm()                                    /*;check_unterm*/
  881. {
  882.     if (INC(MY_NUM_NOTERM) == 0) {
  883.         INC(TCB_NUM_NOTERM(MY_MASTER_TASK));
  884.         INC(BF_NUM_NOTERM(MY_MASTER_TASK, MY_MASTER_BLOCK));
  885.     }
  886. }
  887.  
  888. static void tell_termination(int block)                    /*;tell_termination*/
  889. {
  890.     int i, j, dep, task;
  891.  
  892.     task = BF_SUBTASKS(tp, block);
  893.     while (task != NULL_TASK) {
  894.         i = 0; 
  895.         j = 0;
  896.         while (i < RTS_MULT(TCB_RTS_ITEM(task)))
  897.             if ((dep=RTS_TCBS(TCB_RTS_ITEM(task),j++)) != NULL_TASK) {
  898.                 i++;
  899.                 if ((TCB_STATUS(dep) != TERMINATED)
  900.                   && (INC(TCB_ABNORMAL(dep)) == 0))
  901.                     make_ready(dep, TERMINATE_EVENT);
  902.             }
  903.         task = TCB_BROTHER(task);
  904.     }
  905. }
  906.  
  907. /* Procedure used when an exception is raised to terminate tasks that have
  908.  * created, but not yet activated.(LRM 9.3(4)) Such tasks may have pending
  909.  * rendezvous. All tasks linked to task frames depending on the current BFP
  910.  * are made terminated. They are linked together and put on bf_subtasks in
  911.  * order to release their space when the block is exited.
  912.  */
  913.  
  914. void terminate_unactivated()                     /*;terminate_unactivated */
  915. {
  916.     int     current, next, removed, dep, i, j;
  917.     int    *task_frame;
  918.  
  919.     task_frame = MY_TASKS_DECLARED;
  920.     if (task_frame != (int *)0) {
  921.         removed = NULL_TASK;
  922.         *(task_frame - WORDS_PTR - 1) = -(*(task_frame - WORDS_PTR - 1));
  923.         for (;;) {
  924.             current = *task_frame;
  925.             if (current != NULL_TASK) {
  926.                 for (;;) {
  927.                     i = 0; 
  928.                     j = 0;
  929.                     while (i < RTS_MULT(TCB_RTS_ITEM(current)))
  930.                         if ((dep=RTS_TCBS(TCB_RTS_ITEM(current),j++))
  931.                           != NULL_TASK) {
  932.                             i++;
  933.                             TCB_STATUS(dep) = TERMINATED;
  934.                             purge_rdv(dep);
  935.                         }
  936.                     next = TCB_BROTHER(current);
  937.                     if (next == NULL_TASK)
  938.                         break;
  939.                     current = next;
  940.                 }
  941.  
  942.                 /* we are still in the context of the last task on the chain
  943.                  * merge the chain with previous one
  944.                  */
  945.  
  946.                 TCB_BROTHER(current) = removed;
  947.                 removed = *task_frame;/* head of the chain */
  948.             }
  949.             task_frame = *((int **)(task_frame - WORDS_PTR));
  950.             if (task_frame == (int *)0)
  951.                 break;
  952.         }
  953.  
  954.         if (removed != NULL_TASK)  /* merge on bf_subtasks to release space */
  955.             MY_SUBTASKS = union_tasks_declared(removed, MY_SUBTASKS);
  956.         MY_TASKS_DECLARED = (int *)0;
  957.     }
  958. }
  959.  
  960. /* Procedure to raise TASKING_ERROR in all tasks waiting for or engaged   */
  961. /* in a rendezvous with the currently active task                         */
  962.  
  963. void purge_rdv(int curr)                                        /*;purge_rdv */
  964. {
  965.     int     task, i;
  966.  
  967.     for (i = 1; i <= TCB_NUM_ENTRIES(curr); i++)
  968.         while (ENTRY_COUNT(TCB_ENTRY(curr,i)) > 0) {
  969.             DEC(ENTRY_COUNT(TCB_ENTRY(curr,i)));
  970.             if ((task = eget(TCB_ENTRY(curr,i))) != NULL_TASK) {
  971.                 TCB_EXCEPTION(task) = TASKING_ERROR;
  972.                 make_ready(task, TASKERR_EVENT);
  973.             }
  974.         }
  975.  
  976.     task = TCB_SERVICED(curr);
  977.     while (task != NULL_TASK) {
  978.         TCB_EXCEPTION(task) = TASKING_ERROR;
  979.         make_ready(task, TASKERR_EVENT);
  980.         task = TCB_NEXT(task);
  981.     }
  982. }
  983.  
  984. static void uncreate_tasks(int task_list)                /*;uncreate_tasks */
  985. {
  986.     int        task, next, i, j;
  987.     struct rts_item    *item;
  988.  
  989.     task = task_list;
  990.     while (task > 0) {
  991.         next = TCB_BROTHER(task);
  992.         item = TCB_RTS_ITEM(task);
  993.         i = 0; 
  994.         j = 0;
  995.         while (i < RTS_MULT(item))
  996.             if ((task = RTS_TCBS(item,j++)) != NULL_TASK) {
  997.                 i++;
  998.                 efree((char *) STACK(task));
  999.                 STACK(task) = (int *) 0;
  1000.                 ORIG(task) = NULL_TASK;
  1001.             }
  1002.         task = next;
  1003.     }
  1004. }
  1005.  
  1006. /*--------------------------------------------------------------------------*/
  1007. /*                  T I M E   M A N A G E M E N T                           */
  1008. /*                                                                          */
  1009. /*      The following set of routines perform time management for "delay"   */
  1010. /*  statements.   The chain of waiting tasks associated with each PE        */
  1011. /*  is sorted in ascending time of end of delay.  The time associated       */
  1012. /*  with each entry in the chain in the amount of time it must wait after   */
  1013. /*  the previous entry is done (e.g.  the wait time is kept incrementally)  */
  1014. /*  A global variable "next_clock" keeps the absolute time value of the next*/
  1015. /*  interrupt.  When the interrupt processing routine is called all interupt*/
  1016. /*  which are now ready -or- were previously ready are made ready.          */
  1017. /*    Io_items are freed by either the owning task or the interrupt       */
  1018. /*  process.  If the io_item has been disabled, it is freed by the catcher  */
  1019. /*  routine.  Otherwise it is freed by the process when it awakens from     */
  1020. /*  make ready.                                                             */
  1021. /*--------------------------------------------------------------------------*/
  1022.  
  1023.  
  1024. static void my_set_timer(struct io_item_type *item, long now) /*;my_set_timer*/
  1025. {
  1026.     next_clock = II_DELTA(item) + now;
  1027. }
  1028.  
  1029. static int long my_reset_timer(long now)                /*;my_reset_timer*/
  1030. {
  1031.     last_time = now;
  1032.     return(next_clock - now);
  1033. }
  1034.  
  1035. /*--------------------------------------------------------------------------*/
  1036. /*                              DELAY_STMT                                  */
  1037. /*  Guarantees that all wait times are positive (provided for compatability)*/
  1038. /*  Note that it recognizes three types of delays:                          */
  1039. /*      0       - signifies simply a request to context switch              */
  1040. /*      ENDLESS - signifies simply relinquishing the CPU                    */
  1041. /*      other   - actual create a timer chain element and chain it          */
  1042. /*--------------------------------------------------------------------------*/
  1043.  
  1044. void delay_stmt(long delay_time)                                /*;delay_stmt*/
  1045. {
  1046.     long effective_delay;
  1047.  
  1048.     effective_delay = delay_time >= 0 ? delay_time : 0;
  1049. #ifdef GWUMON
  1050.             CWK_CHANGE_TASK_STAT(tp, 'D', "", "" );
  1051. #endif
  1052. #ifdef TRACE
  1053.     if (rendezvous_trace) {
  1054.         printf("task %d delaying %ld effective delay %ld \n", tp,
  1055.           delay_time, effective_delay);
  1056.     }
  1057. #endif
  1058.     if (effective_delay == (long) ENDLESS)
  1059.         schedule(NO_ACTION);
  1060.     else if (effective_delay == 0)
  1061.         context_switch();
  1062.     else
  1063.         wait(effective_delay, WAIT);
  1064. }
  1065.  
  1066. /*--------------------------------------------------------------------------*/
  1067. /*                                 WAIT                                     */
  1068. /*  Routines which makes the task wait for the delay time                   */
  1069. /*--------------------------------------------------------------------------*/
  1070.  
  1071. static void wait(long delay, int action)                             /*;wait*/
  1072. {
  1073.     MY_STATUS = WAIT;
  1074.     if (MY_ABNORMAL && MY_STATUS != TERMINATED) { 
  1075.         abortme(); 
  1076.         return; 
  1077.     }
  1078.     MY_IO_ITEM = chain(tp, delay);
  1079.     schedule(action);
  1080. }
  1081.  
  1082. static void post_wait()                                            /*;post_wait*/
  1083. {
  1084.     MY_STATUS = ACTIVE;
  1085.     if (MY_ABNORMAL) 
  1086.         abortme(); 
  1087. }
  1088.  
  1089. /*--------------------------------------------------------------------------*/
  1090. /*                              CATCHER                                     */
  1091. /* Routine called when a timer interrupt occurs.                           */
  1092. /*--------------------------------------------------------------------------*/
  1093.  
  1094. void clock_interrupt(long now_time)                     /*;clock_interrupt*/
  1095. {
  1096.     catcher(now_time);
  1097.     context_switch();
  1098. }
  1099.  
  1100. static void catcher(long now_time)                                 /*;catcher*/
  1101. {
  1102.     struct io_item_type    *item;
  1103.     long            time;
  1104.  
  1105.     /* Time Out head of io_item list and all others following with delta 0 */
  1106.     time = now_time - last_time;
  1107.     last_time = now_time;
  1108.  
  1109.     while ((clock_head != NULL) && (II_DELTA(clock_head)<=time)) {
  1110.         item = II_NEXT(clock_head);  /* TO others waiting in interval */
  1111.         time -= II_DELTA(clock_head);
  1112.         check_free(clock_head);
  1113.         clock_head = item;
  1114.     }
  1115.  
  1116.     /* remove interior deletes from head of list */
  1117.  
  1118.     item = clock_head;
  1119.     while ((clock_head != NULL) && (II_FLAG(clock_head) == 0)) {
  1120.         time -= II_DELTA(clock_head);
  1121.         item = II_NEXT(clock_head);
  1122.         efree((char *) clock_head);
  1123.         clock_head = item;
  1124.     }
  1125.     if (clock_head != NULL) {
  1126.         II_DELTA(clock_head) -= time;
  1127.         my_set_timer(clock_head, now_time);
  1128.     }
  1129.     else next_clock_flag = FALSE;
  1130. }
  1131.  
  1132. /*--------------------------------------------------------------------------*/
  1133. /*                                CHAIN                                     */
  1134. /*  Called when execute a delay.  Add task to timeout chain                 */
  1135. /*--------------------------------------------------------------------------*/
  1136.  
  1137. static struct io_item_type *chain(int task, long delay)         /*;chain*/
  1138. {
  1139.     long    my_reset_time(), itime();
  1140.     long    now;
  1141.     struct io_item_type *new_item, *item, *prev_item;
  1142.  
  1143.     now = itime() + time_offset;
  1144.     if (TCB_IO_ITEM(task) == NULL) {
  1145.         new_item=(struct io_item_type *)malloc(sizeof(struct io_item_type));
  1146.         if (new_item == (struct io_item_type *)0) {
  1147.             raise(STORAGE_ERROR, "Allocating space for timer chain");
  1148.             return(NULL);
  1149.         }
  1150.     }
  1151.     else new_item = TCB_IO_ITEM(task);
  1152.     if (clock_head == NULL) {
  1153.         clock_head = new_item;
  1154.         II_TASK(new_item) = task;
  1155.         II_FLAG(new_item) = TCB_STATUS(task);
  1156.         II_NEXT(new_item) = NULL;
  1157.         II_DELTA(new_item) = delay;
  1158.     }
  1159.     else {
  1160.         II_DELTA(clock_head) = my_reset_timer(now); /* time in intval*/
  1161.         II_TASK(new_item) = task;
  1162.         II_FLAG(new_item) = TCB_STATUS(task);
  1163.  
  1164.         /* seq. search for new_item's position based on relative deltas */
  1165.         if (delay <= II_DELTA(clock_head)) {
  1166.             II_NEXT(new_item) = clock_head;
  1167.             II_DELTA(new_item) = delay;
  1168.             II_DELTA(clock_head) -= delay;
  1169.             clock_head = new_item;
  1170.         }
  1171.         else {
  1172.             item = clock_head;
  1173.             prev_item = clock_head;
  1174.             while ((item != NULL) && (delay-II_DELTA(item) > 0)) {
  1175.                 delay -= II_DELTA(item);
  1176.                 prev_item = item;
  1177.                 item = II_NEXT(item);
  1178.             }
  1179.             II_NEXT(new_item) = item;
  1180.             II_NEXT(prev_item) = new_item;
  1181.             II_DELTA(new_item) = delay;
  1182.             if (item != NULL)
  1183.                 II_DELTA(item) -= delay;
  1184.         }
  1185.     }
  1186.     next_clock_flag = TRUE;
  1187.     my_set_timer(clock_head, now);
  1188.     return(new_item);
  1189. }
  1190.  
  1191. /*--------------------------------------------------------------------------*/
  1192. /*                              CHECK  FREE                                 */
  1193. /* Called by catcher to see if timeout is possible                          */
  1194. /*--------------------------------------------------------------------------*/
  1195.  
  1196. static void check_free(struct io_item_type *item)                /*;check_free*/
  1197. {
  1198.     int    value;
  1199.  
  1200.     value = get_io(item);
  1201.     if (value > 0)     /* anything else being waited for has been disble */
  1202.         make_ready(II_TASK(item), TIMER_EVENT);
  1203.  
  1204.     /*  Originally we were going to deallocate the io_item.  This was later
  1205.      *  changed EXCEPT in the case where it was already disabled ...
  1206.      */
  1207.     else if (value == -1)
  1208.         efree((char *) item);
  1209. }
  1210.  
  1211. /*--------------------------------------------------------------------------*/
  1212. /*                                GET  IO                                   */
  1213. /*--------------------------------------------------------------------------*/
  1214.  
  1215. static int get_io(struct io_item_type *item)                        /*;get_io*/
  1216. {
  1217.     int    wake;
  1218.  
  1219.     switch (FAS(&(II_FLAG(item)),TIMER_EVENT)){  /* was task's status */
  1220.     case DISABLED_EVENT:  
  1221.         wake = -1; 
  1222.         break;      /* already gone */
  1223.     case TIMED_RDV :      
  1224.         wake = eremove(II_TASK(item));
  1225.         FAS(&(II_FLAG(item)), 0);        
  1226.         break;
  1227.     case SELECTING_NOTERM:                 /* disable */
  1228.     case SELECTING_TERM:  
  1229.         wake = FAS(&(TCB_RDV(II_TASK(item))),0);
  1230.         FAS(&(II_FLAG(item)), 0);        
  1231.         break;
  1232.     case WAIT :           
  1233.         wake = 1; 
  1234.         break;        /* must wake up */
  1235.     case 0    :           
  1236.         wake = -1; 
  1237.         break;       /* innner remove*/
  1238.     default :             
  1239.         raise(SYSTEM_ERROR, "Unexpected event");
  1240.         break;
  1241.     }
  1242.     II_FLAG(item) = 0;
  1243.     return wake;
  1244. }
  1245.  
  1246.  
  1247. /*--------------------------------------------------------------------------*/
  1248. /*                             DISABLE IO                                   */
  1249. /* Called when rdv ti disable timeouts.  No timeouts possible, but avoids   */
  1250. /* race (that item.flag may be gotten, rendezvous, then RDV reset for next  */
  1251. /* rendezvous).                                                             */
  1252. /*--------------------------------------------------------------------------*/
  1253.  
  1254. static void disable_io(struct io_item_type **item_ptr)            /*;disable_io*/
  1255. {
  1256.     struct io_item_type    *item;
  1257.  
  1258.     item = *item_ptr;
  1259.     if (item != (struct io_item_type*)0) {
  1260.         if (FAS(&(II_FLAG(item)),DISABLED_EVENT) == TIMER_EVENT) {
  1261.             /* Timeout in progress, wait for it to end then delete */
  1262.             while (II_FLAG(item) != 0) continue;
  1263.             efree((char *) item);
  1264.         }
  1265.         *item_ptr =(struct io_item_type *)0 ;
  1266.     }
  1267. }
  1268.  
  1269. /*--------------------------------------------------------------------------*/
  1270. /*                             REMOVE  IO                                   */
  1271. /* Called when abort in delay                                               */
  1272. /*--------------------------------------------------------------------------*/
  1273.  
  1274. static int remove_io(struct io_item_type **item_ptr)            /*;remove_io */
  1275. {
  1276.     struct io_item_type    *item;
  1277.  
  1278.     item = *item_ptr;
  1279.     if (item != (struct io_item_type *)0)
  1280.         if (FAS(&(II_FLAG(item)),DISABLED_EVENT) == TIMER_EVENT) {
  1281.             efree((char *) item);  /* too late, has timed out ... */
  1282.             *item_ptr = (struct io_item_type *)0;
  1283.             return 0;
  1284.         }
  1285.     return 1;
  1286. }
  1287.  
  1288. /*--------------------------------------------------------------------------*
  1289.  *                           S C H E D U L E R                              *
  1290.  *                                                                          *
  1291.  *    The following set of routines perform decentralized scheduling based  *
  1292.  *  on two different schemes: "run-until-blocked" or "round-robin". Because *
  1293.  *  the interpreter simply simulates tasks, it is absolutely necessary that *
  1294.  *  once "schedule" is call and control is  passed to a new virtual task,   *
  1295.  *  that the interpretor return to the highest level without executing any  *
  1296.  *  other code (excepting the cleanup routines  called in "schedule").      *
  1297.  *    Thus any statement which (recursively) executes "schedule" must be    *
  1298.  *  immediately succeeded by a return statement.  The "dangerous" routines  *
  1299.  *  in the system are:                                                      *
  1300.  *                                                                          *
  1301.  *    - activate_self        - abort            - abortme           *
  1302.  *    - complete_task        - complete_task_one    - task_term         *
  1303.  *    - complete_block    - post_complete_block                *
  1304.  *    - wait            - post_wait        - delay_stmt        *
  1305.  *    - entry_call        - post_entry_call    - end_rendezvous    *
  1306.  *    - selective_wait    - post_selective_wait                    *
  1307.  *--------------------------------------------------------------------------*/
  1308.  
  1309. /*--------------------------------------------------------------------------*
  1310.  *                             SCHEDULE                                     *
  1311.  * Block the currently executing task and select a new task to run.         *
  1312.  *--------------------------------------------------------------------------*/
  1313.  
  1314. static void schedule(int action)                                /*;schedule*/
  1315. {
  1316.     int     done, p, i;
  1317.     struct rts_item    *item;
  1318.  
  1319.     MY_ACTION = action;
  1320.     if (DEC(MY_NUM_EVENTS) > 0) {
  1321.         finish_action(MY_RTS_ITEM);  /* an event is waiting */
  1322.         return;
  1323.     }
  1324.     if (action == CONTEXT_SWITCH) INC(MY_NUM_EVENTS);
  1325.     done = FALSE;
  1326.     while (!done) {
  1327.         for (p=MAX_PRIO-1;p>=0;p--) {
  1328.             item = dequeue(ready_queue[p], &i);
  1329.             if (item != (struct rts_item *)0) {
  1330.                 switch(RTS_TYPE(item)) {
  1331.                 case ACTIVATE :
  1332.                 case READY :
  1333. #ifdef GWUMON
  1334.                     CWK_CHANGE_TASK_STAT(item->tcbs[i], 'S', "", "" );
  1335. #endif
  1336. #ifdef TRACE
  1337.                     if (context_sw_trace && (action != DONE_CREATION)) {
  1338.                     /* Don't print internal CS during creation */
  1339.                     /* i.e. task x switching to itself. */
  1340.                         printf("task %d switching to task %d \n",
  1341.                             tp,item->tcbs[i]);
  1342.                     }
  1343. #endif
  1344.                     highest_priority = p;
  1345.                     transfer(item->tcbs[i]);
  1346.                     done = TRUE;
  1347.                     break;
  1348.                 case CREATE :
  1349.                     create_task(RTS_TEMPL_BASE(item),
  1350.                         RTS_TEMPL_OFF(item),item,i);
  1351.                     break;
  1352.                 default :
  1353.                     raise(SYSTEM_ERROR, "Unexpected type");
  1354.                     break;
  1355.                 }
  1356.                 break;   /* out of for loop */
  1357.             }
  1358.             else if (p == 0) done = TRUE;  /* end loop (error) */
  1359.         }
  1360.     }
  1361.  
  1362.     if (item == (struct rts_item *)0)
  1363.     { /* No active task was found, error condition */
  1364.         MY_STATUS = ACTIVE;
  1365.         raise(SYSTEM_ERROR, "No activatable task");
  1366.         MY_EXCEPTION = 0;
  1367.         return;
  1368.     }
  1369.     finish_action(item);
  1370. }
  1371.  
  1372. /* Now the new task is processing.  It must perform the appropriate   */
  1373. /* cleanup routine based on the action which it was performing before */
  1374. /* making the call to the scheduler ...                      */
  1375.  
  1376. static void finish_action(struct rts_item *item)            /*;finish_action*/
  1377. {
  1378.     int    open_en[MAX_ALTS], accept_index[MAX_ALTS];
  1379.     long     sleep_time;
  1380.     long    itime();
  1381.  
  1382.     switch (MY_ACTION) {
  1383.     case WAIT         : 
  1384.         post_wait();             
  1385.         break;
  1386.     case SELECTIVE_WAIT     : 
  1387.         post_selective_wait(0, 0, open_en, accept_index);         
  1388.         break;
  1389.     case ENTRY_CALL     : 
  1390.         post_entry_call();         
  1391.         break;
  1392.     case COMPLETE_BLOCK_ONE    : 
  1393.         post_complete_block();     
  1394.         break;
  1395.     case COMPLETE_BLOCK_TWO : 
  1396.         post_complete_block_two(); 
  1397.         break;
  1398.     case ABORT_ONE        : 
  1399.         post_abort_one();         
  1400.         break;
  1401.     case COMPLETE_TASK_ONE    : 
  1402.         post_complete_task_one();    
  1403.         break;
  1404.     case FREE_TASK_SPACE     : 
  1405.         free_task_space();    
  1406.         break;
  1407.     case DONE_ACTIVATION    : 
  1408.         done_activation();        
  1409.         break;
  1410.     case DONE_CREATION       : 
  1411.         done_creation();        
  1412.         break;
  1413.     case ACTIVATE_SELF      : 
  1414.         activate_self(RTS_MASTER_TASK(item), RTS_MASTER_BLOCK(item)); 
  1415.         break;
  1416.     case CONTEXT_SWITCH    :
  1417.     case NO_ACTION       :                 
  1418.         break;
  1419.     default : 
  1420.         raise(SYSTEM_ERROR, "Tasks awakened in an unknown state");
  1421.         MY_EXCEPTION = 0;                 
  1422.         break;
  1423.     }
  1424.  
  1425.     /* then see if someone else waiting to be scheduled */
  1426.  
  1427.     if (tp == 0) {        /* we schedule IDLE */
  1428.         if (next_clock_flag) {           /* exists task waiting? */
  1429.             if (simul_time_flag)         /* speed up time! */
  1430.                 time_offset += next_clock - itime();
  1431.             else if ((sleep_time=(next_clock-itime())/1000L) > 1L)
  1432.                 sleep((unsigned)sleep_time);
  1433.         }
  1434.         else if ((MY_ACTION != DONE_CREATION) && (MY_ACTION != DONE_ACTIVATION))
  1435.             raise(PROGRAM_ERROR, "System inactive(deadlock)");
  1436.     }
  1437.     MY_ACTION = NO_ACTION;
  1438. }
  1439.  
  1440. /*--------------------------------------------------------------------------*/
  1441. /*                              MAKE READY                                  */
  1442. /* Moves the specified task to the ready queue setting it's event flag.     */
  1443. /*--------------------------------------------------------------------------*/
  1444.  
  1445. static void make_ready(int task, int event)                    /*;make_ready*/
  1446. {
  1447.     if (event != NO_EVENT) /* Mulitple events may overwrite (COMP,TERM,ABORT) */
  1448.         TCB_EVENT(task)=event;  /* but task can tell if correct one happened */
  1449.  
  1450.     if (INC(TCB_NUM_EVENTS(task)) == -1) enqueue(TCB_PRIO(task), task);
  1451. }
  1452.  
  1453. /*--------------------------------------------------------------------------*/
  1454. /*                              ROUND ROBIN                                 */
  1455. /*                                                                          */
  1456. /* Procedure called when the round-robin scheme is invoked. First, detect   */
  1457. /* (asynchronously !) if there is a ready task of higher or same priority   */
  1458. /* than the task blocked. If yes, perform the context_switch.               */
  1459. /* WARNING: the task blocked by the round-robin scheme has still the        */
  1460. /*          status ACTIVE !!!                                               */
  1461. /*                                                                          */
  1462. /*--------------------------------------------------------------------------*/
  1463.  
  1464. void round_robin()                            /*;round_robin*/
  1465. {
  1466.     int p, found;
  1467.  
  1468.     /* is it worth doing a context-switch ? */
  1469.     /* --> test if there is one ready task of higher or same priority */
  1470.     /* warning: asynch test (Cf dequeue with DEC & INC)   */
  1471.  
  1472.     found = FALSE;
  1473.     for (p=MAX_PRIO-1; p>=MY_PRIO; p--)
  1474.         if (ready_queue[p]->count >= 1)
  1475.             found = TRUE;
  1476.     if (found)
  1477.         context_switch();
  1478. }
  1479.  
  1480. /*---------------------------------------------------------------------------*/
  1481. /*                              TRANSFER                                     */
  1482. /*  Transfers control from the currently executing task to the one specified */
  1483. /*---------------------------------------------------------------------------*/
  1484.  
  1485. static void transfer(int new_task)                          /*;transfer*/
  1486. {
  1487.     PUSH(exr);
  1488.     PUSH(lin);
  1489.     PUSH(sfp);
  1490.     PUSH(cs);
  1491.     PUSH(ip);
  1492.     PUSH(bfp);    /*  ----------MUST be on top of stack----------  */
  1493.     MY_BLOCK_PTR = (int *) (cur_stack+cur_stackptr);
  1494.     STACKPTR(tp) = cur_stackptr;
  1495.  
  1496.     tp = new_task;
  1497.     rr_counter = 0;
  1498.     cur_stack = STACK(tp);
  1499.     cur_stackptr = STACKPTR(tp);
  1500.     POP(bfp);
  1501.     MY_BLOCK_PTR = &bfp;
  1502.     POP(ip);
  1503.     POP(cs);
  1504.     POP(sfp);
  1505.     POP(lin);
  1506.     POP(exr);
  1507.     cur_code = code_segments[cs];
  1508. }
  1509.  
  1510. /*--------------------------------------------------------------------------*
  1511.  *                           R E N D E Z V O U S                            *
  1512.  *                                                                          *
  1513.  * The following set of procedures are used to performs rendezvous.  They   *
  1514.  * are divided into two sets: those used to perform a "select" call and     *
  1515.  * those used to execute an "entry" call.    They make use of the parallel  *
  1516.  * queue routines and use the "rdv" flag, the array of "entry" records, the *
  1517.  * "io_item" when processing delays as well as checking and setting the     *
  1518.  * "status" and "abnormal" fields in the caller and/or owner task's TCB.    *
  1519.  * The routines which are called by the interpretor directly are:           *
  1520.  *     - selective_wait                                                    *
  1521.  *     - end_rendezvous                                                    *
  1522.  *     - entry_call                                                        *
  1523.  * There calling interface (stack upon entry and return as well as parms.   *
  1524.  * passed are identical to the original system.                             *
  1525.  *--------------------------------------------------------------------------*/
  1526.  
  1527.  
  1528. /*--------------------------------------------------------------------------*
  1529.  *                          SELECTIVE WAIT                                  *
  1530.  *--------------------------------------------------------------------------*/
  1531.  
  1532. void selective_wait(int num_alts)                            /*;selective_wait */
  1533. {
  1534.     int    alt_kind;        /* delay, terminate or accept */
  1535.     long    delay_time;        /* value of delay */
  1536.     long    min_delay;        /* minimum delay */
  1537.     int    family;            /* family index of entry */
  1538.     int    member;            /* member of family */
  1539.     int    guard;            /* guard of statement (boolean) */
  1540.     int    open_ai[MAX_ALTS];    /* list of open accept indices */
  1541.     int    open_en[MAX_ALTS];    /* list of open entry numbers  */
  1542.     int    num_open_alts;        /* number of open alternatives */
  1543.     int    delay_index;        /* index to delay alt. (or -1) */
  1544.     int    term_index;        /* index to terminate alt. (or -1) */
  1545.     int    accept_index;        /* index to chosen alternative */
  1546.     int     caller;            /* chosen task id of caller */
  1547.     struct entry_type *entry;    /* pointer to entry */
  1548.     int     i, temp;
  1549.  
  1550.  
  1551.     /*  STEP 1: Build a set of open alternatives and determine the shortest
  1552.      * delay and the index set of the terminate (if any)
  1553.      */
  1554.  
  1555.     term_index = -1;
  1556.     min_delay = ENDLESS;
  1557.     delay_index = -1;
  1558.  
  1559.     if (num_alts == 0) {  /* simple accept */
  1560.         POP(member);
  1561.         POP(family);
  1562.         num_open_alts = 1;
  1563.         open_ai[0] = 1;
  1564.         open_en[0] = entry_number(tp, family, member);
  1565.     }
  1566.     else num_open_alts = 0;
  1567.  
  1568.     for (accept_index = num_alts; accept_index >= 1; accept_index --) {
  1569.         POP(alt_kind);
  1570.         if (alt_kind == 1) {    /* accept */
  1571.             POP(member);
  1572.             POP(family);
  1573.             POP(guard);
  1574.             if (guard == 1) {
  1575.                 open_ai[num_open_alts] = accept_index;
  1576.                 open_en[num_open_alts++] = entry_number(tp, family, member);
  1577.             }
  1578.         }
  1579.         else if (alt_kind == 2) {    /* delay */
  1580.             POPL(delay_time);
  1581.             POP(guard);
  1582.             if (guard == 1)
  1583.                 if (delay_index == -1 || delay_time<min_delay) {
  1584.                     min_delay = (delay_time>=0L) ? delay_time : 0L;
  1585.                     delay_index = accept_index;
  1586.                 }
  1587.         }
  1588.         else if (alt_kind == 3) {    /* terminate */
  1589.             POP(guard);
  1590.             if (guard == 1)
  1591.                 term_index = accept_index;
  1592.         }
  1593.         else raise(SYSTEM_ERROR,
  1594.             "Unknown alternative in select statement");
  1595.     }
  1596.  
  1597.     /* STEP 2: Check local status, terminatability, guards, rdv flag etc.  */
  1598.  
  1599.     if (MY_ABNORMAL) { 
  1600.         abortme(); 
  1601.         return; 
  1602.     }
  1603.     MY_STATUS = SELECTING_NOTERM;
  1604.  
  1605.     evaluate_guards(open_en, num_open_alts);
  1606.  
  1607.     FAS(&(MY_RDV), 1);    /* an rdv is now possible     */
  1608.     if (MY_ABNORMAL && (FAS(&(MY_RDV), 0) == 1)) { 
  1609.         abortme(); 
  1610.         return; 
  1611.     }
  1612.  
  1613.     /* STEP 3: See if can start an immediate rendezvous */
  1614.  
  1615.     if (num_open_alts > 0) {
  1616.         i = 0;
  1617.         while (MY_RDV && (i < num_open_alts)) {
  1618.             temp = open_ai[i];
  1619.             entry = MY_ENTRY(open_en[i++]);
  1620.             if (ENTRY_GUARD(entry)) {
  1621.                 del_lock(&(LOCK(entry)));
  1622.                 if ((DEC(ENTRY_COUNT(entry)) > 0) && (FAS(&(MY_RDV),0) == 1)) {
  1623.                     /* a task is waiting and got flag so rdv is possible */
  1624.                     caller = eget(entry);
  1625.                     del_unlock(&(LOCK(entry)));
  1626.                     close_guards(open_en, num_open_alts);
  1627.                     TCB_SAVE_PRIO(caller) = MY_PRIO;
  1628.                     MY_PRIO = MAX(TCB_SAVE_PRIO(caller),MY_PRIO);
  1629.                     accept_rdv(caller,temp,num_alts);
  1630.                     return;
  1631.                 }
  1632.                 else {     /* we did not - disable the rendezvous...  */
  1633.                     INC(ENTRY_COUNT(entry));
  1634.                     del_unlock(&(LOCK(entry)));
  1635.                 }
  1636.             }
  1637.         }
  1638.     }
  1639.  
  1640.     /* STEP 4:  Unfortunately, couldn't perform rendezvous.  Now either detect
  1641.      *    an error condition, try to terminate or delay
  1642.      */
  1643.  
  1644.     if ((num_open_alts == 0) && (delay_index == -1) && (term_index == -1)){
  1645.         raise(PROGRAM_ERROR, "No open alternatives in select");
  1646.         return;
  1647.     }
  1648.  
  1649.     if (MY_RDV == 0) {     /* have been aborted or called, busywait */
  1650.         while ((MY_EVENT != RDV_EVENT) && (!MY_ABNORMAL)) continue;
  1651.         post_selective_wait(1, num_open_alts, open_en, open_ai);
  1652.     }
  1653.     else if ((min_delay == 0) && FAS(&(MY_RDV), 0) == 1) {
  1654.         MY_EVENT = TIMER_EVENT;
  1655.         open_en[num_open_alts] = TIMER_EVENT;
  1656.         open_ai[num_open_alts++] = delay_index;
  1657.         post_selective_wait(1, num_open_alts, open_en, open_ai);
  1658.         return;
  1659.     }
  1660.     else {
  1661.         if (num_alts != 0)    /* push open entry table on stack */
  1662.             for (i=0;i<num_open_alts;i++) {
  1663.                 PUSH(open_en[i]);
  1664.                 PUSH(open_ai[i]);
  1665.             }
  1666.         if (delay_index != -1) {
  1667.             PUSH(TIMER_EVENT);
  1668.             PUSH(delay_index);
  1669.             num_open_alts++;
  1670.         }
  1671.         if (term_index != -1) {
  1672.             PUSH(TERMINATE_EVENT);
  1673.             PUSH(term_index);
  1674.             MY_STATUS = SELECTING_TERM;
  1675.             if (DEC(MY_NUM_NOTERM) == 1)      /* am quiescent */
  1676.                 check_termination(MY_MASTER_TASK, MY_MASTER_BLOCK);
  1677.             num_open_alts++;
  1678.         }
  1679.         if (num_alts == 0)     /* simple accept */
  1680.             PUSH(0); 
  1681.         else  
  1682.             PUSH(num_open_alts); 
  1683.  
  1684. #ifdef GWUMON
  1685.         CWK_CHANGE_TASK_STAT(tp, 'R', "", "" );
  1686. #endif
  1687. #ifdef TRACE
  1688.         if (rendezvous_trace)
  1689.             printf("task %d waiting for a rendezvous \n", tp);
  1690. #endif
  1691.         if (min_delay == ENDLESS) schedule(SELECTIVE_WAIT);
  1692.         else wait(min_delay, SELECTIVE_WAIT);
  1693.     }
  1694. }
  1695.  
  1696.  
  1697. /*--------------------------------------------------------------------------*/
  1698. /*                              EVALUATE GUARDS                             */
  1699. /*--------------------------------------------------------------------------*/
  1700.  
  1701. static void evaluate_guards(int open_en[], int num_open)    /*;evaluate_guards*/
  1702. {
  1703.     int i;
  1704.     struct entry_type    *entry;
  1705.  
  1706.     for (i=0;i< num_open;i++) {
  1707.         entry = MY_ENTRY(open_en[i]);
  1708.         del_lock(&(LOCK(entry)));
  1709.         ENTRY_GUARD(entry) = 1;
  1710.         del_unlock(&(LOCK(entry)));
  1711.     }
  1712. }
  1713.  
  1714. /*--------------------------------------------------------------------------*/
  1715. /*                            CLOSE  GUARDS                                 */
  1716. /*--------------------------------------------------------------------------*/
  1717.  
  1718.  
  1719. static void close_guards(int open_en[], int num_open)        /*;close_guards*/
  1720. {
  1721.     int i;
  1722.     struct entry_type    *entry;
  1723.  
  1724.     for (i=0;i< num_open;i++) {
  1725.         if ((open_en[i] != TERMINATE_EVENT) && (open_en[i] != TIMER_EVENT)){
  1726.             entry = MY_ENTRY(open_en[i]);
  1727.             del_lock(&(LOCK(entry)));
  1728.             ENTRY_GUARD(entry) = 0;
  1729.             del_unlock(&(LOCK(entry)));
  1730.         }
  1731.     }
  1732. }
  1733.  
  1734. /*--------------------------------------------------------------------------*/
  1735. /*                      POST  SELECTIVE  WAIT                               */
  1736. /*--------------------------------------------------------------------------*/
  1737.  
  1738. static void post_selective_wait(int in_mem, int num_alts, int open_en[],
  1739.   int open_ai[])                                    /*;post_selective_wait*/
  1740. {
  1741.     int    status, x, ai, accept_index;
  1742.  
  1743.     status = MY_STATUS;
  1744.     MY_STATUS = ACTIVE;
  1745.     if (MY_ABNORMAL) {
  1746.         if (status == SELECTING_TERM) MY_STATUS = QUIESCENT;
  1747.         abortme();
  1748.         return;
  1749.     }
  1750.     if (status == SELECTING_TERM) check_unterm();
  1751.  
  1752.     /* We must find the accept index for the selected alternative ... */
  1753.     if (MY_EVENT == TIMER_EVENT) MY_WHAT = TIMER_EVENT;
  1754.     accept_index = -1;
  1755.     if (in_mem) {
  1756.         if (num_alts != 0)
  1757.             for (x = 0; x < num_alts; x++)
  1758.                 if (open_en[x] == MY_WHAT) accept_index=open_ai[x];
  1759.     }
  1760.     else {
  1761.         POP(num_alts);
  1762.         if (num_alts != 0)
  1763.             for (x =0 ; x < num_alts; x++) {
  1764.                 POP(ai);
  1765.                 POP(open_en[x]);
  1766.                 if (open_en[x] == MY_WHAT) accept_index = ai;
  1767.             }
  1768.     }
  1769.  
  1770.     if ((num_alts != 0) && (accept_index == -1)) {
  1771.         raise(SYSTEM_ERROR, "Nonexistant alternative selected");
  1772.         return;
  1773.     }
  1774.     close_guards(open_en, num_alts);
  1775.  
  1776.     switch (MY_EVENT) {
  1777.     case TIMER_EVENT : 
  1778.         if (status == WAIT) {
  1779.             efree((char *) MY_IO_ITEM);
  1780.             MY_IO_ITEM = NULL;
  1781.         }
  1782.         PUSH(accept_index);             
  1783.         break;
  1784.     case RDV_EVENT :
  1785.         disable_io(&MY_IO_ITEM);
  1786.         accept_rdv(MY_WHO,accept_index,num_alts); 
  1787.         break;
  1788.     default          : 
  1789.         raise(SYSTEM_ERROR, 
  1790.             "Unexpected event in select/accept"); 
  1791.         break;
  1792.     }
  1793. }
  1794.  
  1795. /*--------------------------------------------------------------------------*/
  1796. /*                               ACCEPT                                     */
  1797. /*--------------------------------------------------------------------------*/
  1798.  
  1799. static void accept_rdv(int caller, int accept_index, int push_index)
  1800.                                                                 /*;accpt_rdv*/
  1801. {
  1802.     int    num_param;    /* number of parameters to transfer */
  1803.     int    disp, i;
  1804.  
  1805.     /* Must copy parameters over from the caller's stack */
  1806.  
  1807.     disp = STACKPTR(caller) - NB_REGISTERS;
  1808.     num_param = STACK(caller)[disp];
  1809.     disp -= num_param + 1;
  1810.     for (i = 1; i <= num_param; i++)
  1811.         PUSH(STACK(caller)[disp+i]);
  1812.  
  1813.     add_serviced(tp, caller);    /* may be nested rdv need if aborted */
  1814.     if (push_index)
  1815.         PUSH(accept_index);
  1816. }
  1817.  
  1818. /*--------------------------------------------------------------------------*/
  1819. /*                          END_RENDEZVOUS                                  */
  1820. /*--------------------------------------------------------------------------*/
  1821.  
  1822. void end_rendezvous()                                        /*;end_rendevous*/
  1823. {
  1824.     int    caller;
  1825.  
  1826.     caller = remove_serviced();
  1827. #ifdef GWUMON
  1828.         CWK_CHANGE_TASK_STAT(caller, 'M', "", "" );
  1829. #endif
  1830. #ifdef TRACE
  1831.     if (rendezvous_trace)
  1832.         printf("task %d end rendezvous with task %d \n",tp, caller);
  1833. #endif
  1834.     MY_PRIO = TCB_SAVE_PRIO(caller);
  1835.     if (MY_EXCEPTION)           /* propagate exception to calling task */
  1836.         TCB_EXCEPTION(caller) = MY_EXCEPTION;
  1837.  
  1838.     make_ready(caller, ENDRDV_EVENT);
  1839.     if (MY_ABNORMAL) {              /* owner aborted, raise TASKING ERROR */
  1840.         TCB_EXCEPTION(caller) = TASKING_ERROR;
  1841.         abortme();
  1842.         return;
  1843.     }
  1844. }
  1845.  
  1846.  
  1847. /*--------------------------------------------------------------------------*/
  1848. /*                         ENTRY  CALL                                      */
  1849. /*--------------------------------------------------------------------------*/
  1850.  
  1851. void entry_call(long delay_time, int num_param)                    /*;entry_call*/
  1852. {
  1853.     struct entry_type *entry;
  1854.     int    owner;            /* owner of entry */
  1855.     int    family;            /* index of family of the entry */
  1856.     int    member;            /* index of member of the entry */
  1857.     int    entry_num;        /* actual entry number */
  1858.  
  1859.     /* STEP 1:  Get calling information from the stack */
  1860.  
  1861.     member = TOSM(num_param);
  1862.     family = TOSM(num_param + 1);
  1863.     owner  = TOSM(num_param + 2);
  1864.     if (is_callable(owner) == FALSE) {
  1865.         switch(TCB_STATUS(owner)) {
  1866.         case TERMINATED:
  1867.             raise(TASKING_ERROR, "Call to an entry of a terminated task");
  1868.             return;
  1869.         case COMPLETED:
  1870.         default:
  1871.             raise(TASKING_ERROR, "Call to an entry of a completed task");
  1872.             return;
  1873.         }
  1874.     }
  1875.     entry_num = entry_number(owner, family, member);
  1876.  
  1877. #ifdef GWUMON
  1878.     CWK_CHANGE_TASK_STAT(tp, 'R', "", "" );
  1879. #endif
  1880. #ifdef TRACE
  1881.     if (rendezvous_trace)
  1882.         printf("task %d calling rendezvous with task %d entry %d\n",
  1883.           tp, owner, entry_num);
  1884. #endif
  1885.  
  1886.     /* STEP 2: Perform some error detection */
  1887.  
  1888.     if (entry_num > TCB_NUM_ENTRIES(owner)) {
  1889.         raise(SYSTEM_ERROR, "Nonexistant entry called");
  1890.         return;
  1891.     }
  1892.  
  1893.     /* STEP 3: Set statuses */
  1894.  
  1895.     if (MY_ABNORMAL) { 
  1896.         abortme(); 
  1897.         return; 
  1898.     }
  1899.     if (delay_time == ENDLESS)
  1900.         MY_STATUS = CALLING_RDV;
  1901.     else MY_STATUS = TIMED_RDV;
  1902.     entry = TCB_ENTRY(owner, entry_num);
  1903.     PUSH(num_param);
  1904.     add_lock(&(LOCK(entry)));
  1905.  
  1906.     /* STEP 4:  See if immediate rendezvous */
  1907.  
  1908.     if ((INC(ENTRY_COUNT(entry)) == 0) && ENTRY_GUARD(entry) &&
  1909.       (FAS(&(TCB_RDV(owner)), 0) == 1)) {
  1910.         /* owner is commited to a rendezvous with the caller */
  1911.         DEC(ENTRY_COUNT(entry));    /* restore counter */
  1912.         TCB_WHAT(owner) = entry_num;
  1913.         TCB_WHO(owner) = tp;
  1914.         add_unlock(&(LOCK(entry)));
  1915.         disable_io(&(TCB_IO_ITEM(owner)));
  1916.         MY_SAVE_PRIO = TCB_PRIO(owner);
  1917.         TCB_PRIO(owner) = MAX(TCB_PRIO(owner),MY_PRIO);
  1918.         make_ready(owner, RDV_EVENT);
  1919.         schedule(ENTRY_CALL);        /* wait for end of rdv */
  1920.     }
  1921.  
  1922.     /* STEP 5: Cannot rendezvous immediately */
  1923.  
  1924.     else {    /* cannot immediately start a rendezvous */
  1925.         if (delay_time == 0) {   /* else changed to "delay 0" */
  1926.             DEC(ENTRY_COUNT(entry));
  1927.             add_unlock(&(LOCK(entry)));
  1928.             cur_stackptr -= 3;
  1929.             PUSH(0);
  1930.         }
  1931.         else {
  1932.             MY_CURR_ENTRY = entry;
  1933.             eput(entry, tp, &MY_ENTRY_ITEM);
  1934.             add_unlock(&(LOCK(entry)));
  1935.             if (MY_ABNORMAL && eremove(tp)) {
  1936.                 abortme();
  1937.                 return;
  1938.             }
  1939.             if (delay_time != ENDLESS)
  1940.                 MY_IO_ITEM = chain(tp, delay_time);
  1941.             schedule(ENTRY_CALL);
  1942.         }
  1943.     }
  1944. }
  1945.  
  1946. /*-------------------------------------------------------------------*/
  1947. /*                       POST  ENTRY  CALL                           */
  1948. /*-------------------------------------------------------------------*/
  1949.  
  1950. static void post_entry_call()                            /*;post_entry_call*/
  1951. {
  1952.     int    num_param;    /* number of parameters */
  1953.     int    i;
  1954.  
  1955.     POP(num_param);
  1956.     if (MY_ABNORMAL)  {
  1957.         disable_io(&MY_IO_ITEM);
  1958.         abortme();
  1959.         return;
  1960.     }
  1961.  
  1962.     i = MY_EVENT;
  1963.     switch (MY_EVENT) {
  1964.     case TIMER_EVENT : 
  1965.         efree((char *) MY_IO_ITEM);
  1966.         MY_IO_ITEM = NULL;
  1967.         cur_stackptr -= 3;
  1968.         PUSH(0);                 
  1969.         break;
  1970.     case ENDRDV_EVENT: 
  1971.         disable_io(&MY_IO_ITEM);
  1972.         if (MY_EXCEPTION)
  1973.             raise(MY_EXCEPTION, "Exception propagated from called task");
  1974.         MY_EXCEPTION = 0;
  1975.         for (i = cur_stackptr - num_param - 3 + 1; i <= cur_stackptr; i++)
  1976.             cur_stack[i] = cur_stack[i+3];
  1977.         cur_stackptr -=3;
  1978.         if (MY_STATUS == TIMED_RDV) 
  1979.             PUSH(1); 
  1980.         break;
  1981.     case TASKERR_EVENT :
  1982.         raise(TASKING_ERROR, "Entry call failed: called task terminated");
  1983.         MY_EXCEPTION = 0;             
  1984.         break;
  1985.     default    : 
  1986.         raise(SYSTEM_ERROR, "Unexpected event in entry call");     
  1987.         break;
  1988.     }
  1989.     MY_STATUS = ACTIVE;
  1990. }
  1991.  
  1992.  
  1993. /*-----------------------------------------------------------------------*/
  1994. /*                       U T I L I T Y    R O U T I N E S                */
  1995. /*-----------------------------------------------------------------------*/
  1996.  
  1997. /*--------------------------------------------------------------------------*/
  1998. /*                          ENTRY  QUEUE  ROUTINES                          */
  1999. /*   The following four routines (einit, eremove, eput & eget) are parallel */
  2000. /*   access queue routines for maintaining the entry queue in tasks' tcbs.  */
  2001. /*--------------------------------------------------------------------------*/
  2002.  
  2003. static void einit(struct entry_type    *entry)                            /*;einit*/
  2004. {
  2005.     ENTRY_LAST(entry) = NULL;
  2006.     ENTRY_FIRST(entry) = NULL;
  2007.     (LOCK(entry)).add_lock = 0;
  2008.     (LOCK(entry)).del_lock = 0;
  2009.     ENTRY_GUARD(entry) = 0;
  2010.     ENTRY_COUNT(entry) = 0;
  2011. }
  2012.  
  2013. static int eremove(int task)                                    /*;eremove*/
  2014. {
  2015.     if ((TCB_ENTRY_ITEM(task) == NULL) || (TCB_CURR_ENTRY(task) == NULL))
  2016.         return FALSE;
  2017.  
  2018.     add_lock(&(LOCK(TCB_CURR_ENTRY(task))));
  2019.     if (FAS(&(ITEM_FLAG(TCB_ENTRY_ITEM(task))), 0) == 0) {
  2020.         add_unlock(&(LOCK(TCB_CURR_ENTRY(task))));
  2021.         return FALSE;
  2022.     }
  2023.     else {
  2024.         DEC(ENTRY_COUNT(TCB_CURR_ENTRY(task)));
  2025.         add_unlock(&(LOCK(TCB_CURR_ENTRY(task))));
  2026.         TCB_CURR_ENTRY(task) = NULL;
  2027.         TCB_ENTRY_ITEM(task) = NULL;
  2028.         return TRUE;
  2029.     }
  2030. }
  2031.  
  2032. static void eput(struct entry_type *entry, int caller, struct q_item **ret_item)
  2033.                                                                     /*;eput*/
  2034. {
  2035.     struct q_item    *prev_item, *item;
  2036.  
  2037.     item = (struct q_item*) malloc(sizeof(struct q_item));
  2038.     if (item == (struct q_item*)0) {
  2039.         raise(STORAGE_ERROR, "Allocating space for entry queue");
  2040.         return;
  2041.     }
  2042.     ITEM_FLAG(item) = 1;
  2043.     ITEM_TASK(item) = caller;
  2044.     ITEM_NEXT(item) = NULL;
  2045.     prev_item =  FAS_Q(&(ENTRY_LAST(entry)), item);
  2046.     if (prev_item == (struct q_item *)0)
  2047.         FAS_Q(&(ENTRY_FIRST(entry)), item);
  2048.     else
  2049.         FAS_Q(&(ITEM_NEXT(prev_item)), item);
  2050.     *ret_item = item;
  2051. }
  2052.  
  2053. static int eget(struct entry_type *entry)                            /*;eget*/
  2054. {
  2055.     struct q_item        *caller, *new_caller;
  2056.     int            task;
  2057.  
  2058.     del_lock(&(LOCK(entry)));
  2059.     if (ENTRY_FIRST(entry) == NULL) {
  2060.         del_unlock(&(LOCK(entry)));
  2061.         return NULL_TASK;
  2062.     }
  2063.  
  2064.     ENTRY_GUARD(entry) = 0;
  2065.     caller = FAS_Q(&(ENTRY_FIRST(entry)), (ITEM_NEXT(ENTRY_FIRST(entry))));
  2066.     while ((caller != (struct q_item*)0) && (FAS(&(ITEM_FLAG(caller)),0) == 0)){
  2067.         new_caller = FAS_Q(&(ENTRY_FIRST(entry)),ITEM_NEXT(ENTRY_FIRST(entry)));
  2068.         efree((char *) caller);
  2069.         caller = new_caller;
  2070.     }
  2071.  
  2072.     if (caller != (struct q_item*)0) {
  2073.         if (TCB_IO_ITEM(ITEM_TASK(caller)) != NULL)
  2074.             disable_io(&(TCB_IO_ITEM(ITEM_TASK(caller))));
  2075.         if (ENTRY_COUNT(entry) == 0) FAS_Q(&(ENTRY_LAST(entry)), NULL);
  2076.         task = ITEM_TASK(caller);
  2077.         efree((char *) caller);
  2078.         TCB_ENTRY_ITEM(task) = (struct q_item *)0;
  2079.     }
  2080.     else task = NULL_TASK;
  2081.     del_unlock(&(LOCK(entry)));
  2082.     return(task);
  2083. }
  2084.  
  2085. /*---------------------------------------------------------------------------*
  2086.  *                           LOCKING  ROUTINES                               *
  2087.  *                                                                           *
  2088.  * Locks on entries may be either "add" locks or "del" locks.  "del" (or     *
  2089.  * delete) locks have precedence over "add" locks.  These are implemented    *
  2090.  * using a standard A-B locking scheme.                                      *
  2091.  *---------------------------------------------------------------------------*/
  2092.  
  2093. static void add_lock(struct lock_type *lock)                    /*;add_lock*/
  2094. {
  2095.     for (;;) {
  2096.         while (lock->del_lock > 1) continue;  /* wait for dels to end */
  2097.         INC(lock->add_lock);             /* try tp get add lock  */
  2098.         if (lock->del_lock > 1)               /* oops, del started... */
  2099.             DEC(lock->add_lock);
  2100.         else break;
  2101.     }
  2102. }
  2103.  
  2104. static void add_unlock(struct lock_type *lock)                    /*;add_unlock*/
  2105. {
  2106.     DEC(lock->add_lock);
  2107. }
  2108.  
  2109. static void del_lock(struct lock_type *lock)                    /*;del_lock */
  2110. {
  2111.     INC(lock->del_lock);         /* don't allow adds to start */
  2112.     while (lock->add_lock > 1) continue;  /* wait for adds to end */
  2113. }
  2114.  
  2115. static void del_unlock(struct lock_type *lock)                    /*;del_unlock*/
  2116. {
  2117.     DEC(lock->del_lock);
  2118. }
  2119.  
  2120. /*-----------------------------------------------------------------------*/
  2121. /*                          ENTRY NUMBER                                 */
  2122. /*-----------------------------------------------------------------------*/
  2123.  
  2124. static int entry_number(int owner, int family, int member)    /*;entry_number*/
  2125. {
  2126.     return (*ADDR(TCB_TBASE(owner), TCB_TOFF(owner) + 2 * (family -1))
  2127.       + member + 1);
  2128. }
  2129.  
  2130. /*------------------------------------------------------------------------*
  2131.  *                          RAISE  IN  CALLER                             *
  2132.  * Procedure to raise an exception in the task waiting for the completion *
  2133.  * of the current rendezvous                          *
  2134.  * -----------------------------------------------------------------------*/
  2135.  
  2136. void raise_in_caller()                                    /*;raise_in_caller*/
  2137. {
  2138. #ifdef GWUMON
  2139.         CWK_CHANGE_TASK_STAT(tp, 'B', "", "" );
  2140.         {
  2141.         char msg[240];
  2142.         sprintf(msg, "task %d raising exception %s in task %d\n",tp,
  2143.           exception_slots[exr],MY_SERVICED);
  2144.         CWK_Exception_Raised( tp, msg );
  2145.         }
  2146. #endif
  2147. #ifdef TRACE
  2148.     if (exception_trace)
  2149.         printf("task %d raising exception %s in task %d\n",tp,
  2150.           exception_slots[exr],MY_SERVICED);
  2151. #endif
  2152.     TCB_EXCEPTION(MY_SERVICED) = exr;
  2153. }
  2154.  
  2155.  
  2156. /* -----------------------------------------------------------------------*
  2157.  *                           ATTRIBUTE  ROUTINES                          *
  2158.  *  The following three routines (is_callable, is_terminated and count)   *
  2159.  *  return the attributes 'CALLABLE, 'TERMINATED and 'COUNT respecitvely  *
  2160.  *  for the given task                                                    *
  2161.  * -----------------------------------------------------------------------*/
  2162.  
  2163. int is_callable(int task)                                    /*;is_callable*/
  2164. {
  2165.     if (task != ORIG(task) || STACK(task) == (int *)0 || TCB_ABNORMAL(task))
  2166.         return FALSE;
  2167.     switch(TCB_STATUS(task)) {
  2168.     case TERMINATED:
  2169.     case ABNORMAL: 
  2170.         return FALSE;
  2171.     case COMPLETED:     /* are we completed on the last level? */
  2172.         return BF_PREVIOUS_BFP(task, *(TCB_BLOCK_PTR(task))) == NULL_TASK;
  2173.     default: 
  2174.         return TRUE;
  2175.     }
  2176. }
  2177.  
  2178. int is_terminated(int task)                                /*;is_terminated*/
  2179. {
  2180.     if (task != ORIG(task) || STACK(task) == (int *)0 )  return TRUE;
  2181.     return (TCB_STATUS(task) == TERMINATED);
  2182. }
  2183.  
  2184. int count(int family, int member)                                /*;count*/
  2185. {
  2186.     return(ENTRY_COUNT(MY_ENTRY(entry_number(tp, family, member))));
  2187. }
  2188.  
  2189. /*---------------------------------------------------------------------------*/
  2190. /*                              MULTISIGNAL                                  */
  2191. /*---------------------------------------------------------------------------*/
  2192.  
  2193. static void multisignal(int task, int event)                 /*;multisignal*/
  2194. {
  2195.     if (event != NO_EVENT) TCB_EVENT(task) = event;
  2196.     if (DEC(TCB_NUM_ITEMS(task)) == 1)
  2197.         make_ready(task, NO_EVENT);
  2198. }
  2199.  
  2200. /*---------------------------------------------------------------------------*/
  2201. /*                            "SERVICED"  QUEUE                              */
  2202. /*---------------------------------------------------------------------------*/
  2203.  
  2204. static void add_serviced(int server, int task)                /*;add_serviced*/
  2205. {
  2206.     TCB_NEXT(task) = FAS(&(TCB_SERVICED(server)), task);
  2207. }
  2208.  
  2209. static int remove_serviced()                            /*;remove_serviced*/
  2210. {
  2211.     return(FAS(&(MY_SERVICED), TCB_NEXT(MY_SERVICED)));
  2212. }
  2213.  
  2214. /*--------------------------------------------------------------------------*/
  2215. /*                             READY  QUEUE                                 */
  2216. /*  The following three routines (qinit, enqueue, enqueue_item and dequeue) */
  2217. /*  are the routines used in accessing the ready queue.  The other three    */
  2218. /*  routines are used to control the scheduler.                             */
  2219. /*--------------------------------------------------------------------------*/
  2220.  
  2221. static void qinit()                                                    /*;qinit*/
  2222. {
  2223.     int    i;
  2224.     struct ready_q    *q;
  2225.  
  2226.     for (i = 0; i < MAX_PRIO; i++) {
  2227.         ready_queue[i] = (struct ready_q *)malloc(sizeof(struct ready_q));
  2228.         q = ready_queue[i];
  2229.         if (q == (struct ready_q *)0) {
  2230.             printf("Unable to allocate stack\n");
  2231.             exit(RC_ABORT);
  2232.         }
  2233.         q->first = NULL;
  2234.         q->last = NULL;
  2235.         q->first_mult = 0;
  2236.         q->count = 0;
  2237.         q->lock.add_lock = 0;
  2238.         q->lock.del_lock = 0;
  2239.     }
  2240. }
  2241.  
  2242. static void enqueue(int priority, int value)                    /*;enqueue*/
  2243. {
  2244.     struct rts_item    *item;
  2245.  
  2246.     item = (struct rts_item *) malloc(sizeof(struct rts_item));
  2247.     if (item == (struct rts_item *)0){
  2248.         raise(STORAGE_ERROR, "Allocating space for ready queue");
  2249.         return;
  2250.     }
  2251.     item->tcbs = (int *) malloc(sizeof(int));
  2252.     if (item->tcbs == (int *)0){
  2253.         raise(STORAGE_ERROR, "Allocating space for ready queue");
  2254.         return;
  2255.     }
  2256.     RTS_TYPE(item) = READY;
  2257.     RTS_PRIO(item) = priority;
  2258.     RTS_MULT(item) = 1;
  2259.     RTS_NEXT(item) = NULL;
  2260.     RTS_TCBS(item, 0) = value;
  2261.     enqueue_item(priority, item);
  2262. }
  2263.  
  2264. static void enqueue_item(int priority, struct rts_item *item)  /*;enqueue_item*/
  2265. {
  2266.     struct ready_q    *q;
  2267.     struct rts_item    *prev;
  2268.  
  2269.     RTS_SAVE_MULT(item) = RTS_MULT(item);
  2270.     q = ready_queue[priority];
  2271.     while (highest_priority < priority)
  2272.         priority = FAS(&highest_priority, priority);
  2273.     add_lock(&(LOCK(q)));
  2274.     prev = FAS_RTS(&(q->last), item);
  2275.     if (prev == (struct rts_item *)0) {
  2276.         FAS_RTS(&(q->first), item);
  2277.         FAS(&(q->first_mult), item->mult);
  2278.     }
  2279.     else    FAS_RTS(&(prev->next), item);
  2280.     q->count += item->mult;
  2281.     add_unlock(&(LOCK(q)));
  2282. }
  2283.  
  2284. static struct rts_item *dequeue(struct ready_q *q, int *i)            /*;dequeue*/
  2285. {
  2286.     struct rts_item    *item;
  2287.     int    j, k;
  2288.  
  2289.     if (q->count <= 0) return (struct rts_item *)0;
  2290.     else if (DEC(q->count) < 1) {
  2291.         INC(q->count);
  2292.         return (struct rts_item *)0;
  2293.     }
  2294.     else {
  2295.         while (q->first_mult > 0 && DEC(q->first_mult) < 1) continue;
  2296.         item = q->first;
  2297.         if ((j = DEC(q->first->mult)) == 1) {  /* remove from list */
  2298.             RTS_MULT(q->first) = RTS_SAVE_MULT(q->first);
  2299.             if (q->first->next == NULL)  {
  2300.                 del_lock(&(LOCK(q)));
  2301.                 if (q->first->next == NULL)  {
  2302.                     FAS_RTS(&q->first, NULL);
  2303.                     FAS_RTS(&q->last, NULL);
  2304.                 }
  2305.                 else {
  2306.                     FAS_RTS(&(q->first), q->first->next);
  2307.                     FAS(&(q->first_mult), q->first->mult);
  2308.                 }
  2309.                 del_unlock(&(LOCK(q)));
  2310.             }
  2311.             else {
  2312.                 FAS_RTS(&(q->first), q->first->next);
  2313.                 FAS(&(q->first_mult), q->first->mult);
  2314.             }
  2315.         }
  2316.         k = 0; 
  2317.         *i = -1;
  2318.         while (k < j)
  2319.             if (item->tcbs[++(*i)] != NULL_TASK) k++;
  2320.         return item;
  2321.     }
  2322. }
  2323.  
  2324. static void context_switch()                                /*;context_switch*/
  2325. {
  2326.     DEC(MY_NUM_EVENTS);
  2327.     make_ready(tp, TIMER_EVENT);
  2328.     schedule(CONTEXT_SWITCH);
  2329. }
  2330.  
  2331. #ifdef IBM_PC
  2332. static void sleep(unsigned secs)
  2333. {
  2334. #ifdef GWUMON
  2335.     if ( type_of_delay == 1 )
  2336.     {
  2337.         long check = itime();
  2338.         check += secs * CLOCKS_PER_SEC;
  2339.         while ( itime() < check )
  2340.         {
  2341.             if ( step_rate == 0 )
  2342.                 busy_wait(1);
  2343.             else
  2344.                 busy_wait(step_rate);
  2345.             CWK_TIME_TASK();
  2346.         }
  2347.     }
  2348.     else
  2349.     {
  2350.         clock_t check = clock();
  2351.         check += secs * CLOCKS_PER_SEC;
  2352.         while (clock() < check)
  2353.             ;
  2354.     }
  2355. #else
  2356.     clock_t check = clock();
  2357.     check += secs * CLOCKS_PER_SEC;
  2358.     while (clock() < check)
  2359.         ;
  2360. #endif
  2361. }
  2362. #endif
  2363.